зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1785002 - Force update hashbrown to 0.12.3. r=emilio,supply-chain-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D154762
This commit is contained in:
Родитель
e629e09f6d
Коммит
790d70c82e
|
@ -1579,7 +1579,7 @@ version = "0.4.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52db5973b6a19247baf19b30f41c23a1bfffc2e9ce0a5db2f60e3cd5dc8895f7"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.11.999",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2374,7 +2374,7 @@ checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"gpu-descriptor-types",
|
||||
"hashbrown",
|
||||
"hashbrown 0.11.999",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2417,9 +2417,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
version = "0.11.999"
|
||||
dependencies = [
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
@ -2430,7 +2437,7 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.11.999",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2600,7 +2607,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
"hashbrown 0.11.999",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
|
@ -125,6 +125,9 @@ tinyvec = { path = "build/rust/tinyvec" }
|
|||
# Patch wasi 0.10 to 0.11
|
||||
wasi = { path = "build/rust/wasi" }
|
||||
|
||||
# Patch hashbrown 0.11 to 0.12
|
||||
hashbrown = { path = "build/rust/hashbrown" }
|
||||
|
||||
# Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30
|
||||
autocfg = { path = "third_party/rust/autocfg" }
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "hashbrown"
|
||||
version = "0.11.999"
|
||||
edition = "2018"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies.hashbrown]
|
||||
version = "0.12"
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
ahash-compile-time-rng = ["hashbrown/ahash-compile-time-rng"]
|
||||
default = ["hashbrown/default"]
|
||||
inline-more = ["hashbrown/inline-more"]
|
||||
nightly = ["hashbrown/nightly"]
|
||||
raw = ["hashbrown/raw"]
|
||||
rustc-dep-of-std = ["hashbrown/rustc-dep-of-std"]
|
||||
rustc-internal-api = ["hashbrown/rustc-internal-api"]
|
|
@ -0,0 +1,5 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
pub use hashbrown::*;
|
|
@ -368,6 +368,12 @@ the usage is pretty straightforward and while it's technically UB, it seems no
|
|||
more likely to lead to miscompilation than any other use of mem::uninitialized.
|
||||
"""
|
||||
|
||||
[[audits.hashbrown]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.12.3"
|
||||
notes = "This version is used in rust's libstd, so effectively we're already trusting it"
|
||||
|
||||
[[audits.hyper]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-run"
|
||||
|
|
|
@ -737,10 +737,6 @@ criteria = "safe-to-deploy"
|
|||
version = "0.3.13"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.hashbrown]]
|
||||
version = "0.11.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hashlink]]
|
||||
version = "0.7.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"CHANGELOG.md":"24ff18c978b40b166f5b3fd1090c3526d1958e79137dd9d765b571fed1c59fc2","Cargo.toml":"98ca6560469b01c01771f3c22c6182497d2239463cb4f63395d8207002d9a9ad","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"742ce1a4c92dada5f73ce594b224b646ff4aefe702768ec2eb39bd937a5a8fd3","benches/bench.rs":"43546a3d5aed2dd8f71f5d236f4df63d82a3767aec90d86f4ab1d1496619b45d","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"d4fbca4db924925548f8dab8eb94cf4a3955a53c5e1ff15f59c460546c394034","src/external_trait_impls/rayon/map.rs":"eee6371f2875085b286e950a32d13c3eff3c7280e7ea6ad346d322e7a00e7b7b","src/external_trait_impls/rayon/mod.rs":"156de9c1ad0123334ea3b7e5a17444faf1b8bf971aa88a1f23e2f2d1c3021141","src/external_trait_impls/rayon/raw.rs":"ddf349051bada9a9ebd027686e03ac2f12d74dd1b3f98a36aac257e13bac57fa","src/external_trait_impls/rayon/set.rs":"c4c44d44e56c2f59e9e1355662e29d8744ac96645ca4414127a359fb46cb0fbf","src/external_trait_impls/serde.rs":"9306fb6e0e339398dc23ba9e7400a9a28d713df248e8b260e3d4dc44f799e101","src/lib.rs":"45cd368e35bdb00232bcf2f5430ee516bb448a88724ab738424ae2e1d3c1f22e","src/macros.rs":"0b1e9a55e8f5232b82f7e56f352a98904b35ddfca015377cf71daa31939baabf","src/map.rs":"f3d43769100c59b04a978c9756e1b32f88cf7a84b9bda0e050a4adf5afb95572","src/raw/alloc.rs":"893da7047ff4eb3291a3dee62c954f489c8b7666aa01ef6aeda8adf2549869c0","src/raw/bitmask.rs":"05e72c64957af7383001ca43a827cc5b3a8a39d00fac332ecea2fd7d2704099c","src/raw/generic.rs":"b31590616e76dfcca635e3aa9a8a0059b3af9a5afe6b0c5ebc98a7d96d63e8ed","src/raw/mod.rs":"a0d0b0508d41e08bfc16e5db1dd4f80cd29ca26e656a803821d1eb56a1f249b3","src/raw/sse2.rs":"a775ddd8830593bb10e2a4a11b2ce16d900a68e0b3763f24715f8f7fa9c2f69d","src/rustc_entry.rs":"148fae9e8bf4893820648c3c80b24c7161c828d103f3b2a2d7bbc32fe6605eb1","src/scopeguard.rs":"808655b3e98512fdcee5a4597e7763a6be99582ba8d77e5ba5ca130d85a97211","src/set.rs":"d64fbadd0e6a5749cb5838f869004ea8cd46cec4b948615f810abb9e0a892d72","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/rayon.rs":"2286707a87b139f41902c82488c355b9fb402a3e734f392f3a73e87b9b932795","tests/serde.rs":"6bac8054db722dd049901b37a6e006535bac30f425eb5cd91af19b5bc1dfe78e","tests/set.rs":"374bd312c01a01cf8953bbbc9494f431b260c2657d7c79cc250e977b869a76ad"},"package":"ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"}
|
||||
{"files":{"CHANGELOG.md":"ade49a29d368e16ce508aee91b477ecbad7e2e52eb6fee7b4c1fc86199963f0e","Cargo.toml":"421b3a71d97faf0a7e52c3b2bfbe0f1c036b9dbf6232b4e5b41221bb54358f5a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"a536b3bb3f3521e59836080f05a4783150fa8484f759a31468ce3b6dba1f33eb","benches/bench.rs":"aadc39d815eadf094ed9357d946319df2d93194203bbccb7c33cea6951d654df","benches/insert_unique_unchecked.rs":"cb84275f22d5f95a5ac995ac6b2df74ffcf342765b401d27c95f2955c7b7cb9f","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"ba105bf0853ebc45157f22116ad0f55d3bdab75e721d8e7a677c7b912d0c0c6d","src/external_trait_impls/rayon/map.rs":"2809e2a0071db8101c38789deb955f3830c5c3455eb1794ff64a0cf2ceb53fc7","src/external_trait_impls/rayon/mod.rs":"156de9c1ad0123334ea3b7e5a17444faf1b8bf971aa88a1f23e2f2d1c3021141","src/external_trait_impls/rayon/raw.rs":"e62c5f3ca5fffea47357e64b6f8c34cec94af62d9bd28a2b87934da46c22b66e","src/external_trait_impls/rayon/set.rs":"c4c44d44e56c2f59e9e1355662e29d8744ac96645ca4414127a359fb46cb0fbf","src/external_trait_impls/serde.rs":"0bc1a1f218d1ae7a5262557a5e3737b9334caf7d50c136dbdc75ff75680c223b","src/lib.rs":"c82fbee9684bfff40ef55d5f0c9f855c11f71f9fd1720fb084ef8331bdbc41d8","src/macros.rs":"36fe532656879c80f7753d13354b889f5b45caef451a1bb3a27dbc32d74c9878","src/map.rs":"df39edae67c569378dea9a4d928685cb4d06569712c6ac36a54df76fb5d87fe3","src/raw/alloc.rs":"184a0345bc2c7544b65c28724063be26b1f2b28dbaaa028a0b01192ccac25557","src/raw/bitmask.rs":"820d90b19b7e3433a1048ace008c9526331cd53a576cb0cfc1ff9960b6fe52f8","src/raw/generic.rs":"f5013a50d6d82d5cc8bad8b8c26c24d00fa810197f9f123256c58ac92e0d98f9","src/raw/mod.rs":"fa38247c6b3bd70636be50400debb9966a3446d49ee13e4f4e2dfe4ceed1b201","src/raw/sse2.rs":"838cfdb1daa1e70951ed25f985283b8b7ab4b46fa130f92eda152047ce6086f6","src/rustc_entry.rs":"cdd70972cba5b79ca1cad79869cb5e184d6dc4798ef90822e966ef89679ba011","src/scopeguard.rs":"d13de1b12897add7fe1c3eba6f906c9cc09d86509b6cfe06b95d63803fe9265c","src/set.rs":"6877d4a42eeadd681e3b8881528e4b20f14cfedbc11e9318bfcf425ef96d1546","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/rayon.rs":"83d5289771542203f539a41cccb889fbe7ce70f5adf5b903ac9f051e3ba13cfa","tests/serde.rs":"6bac8054db722dd049901b37a6e006535bac30f425eb5cd91af19b5bc1dfe78e","tests/set.rs":"01cf39efb04646ef4c63a809ebb96dfa63cfec472bf8bdb6c121f6526d40c40e"},"package":"8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"}
|
|
@ -2,11 +2,67 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.12.3] - 2022-07-17
|
||||
|
||||
## Fixed
|
||||
|
||||
- Fixed double-drop in `RawTable::clone_from`. (#348)
|
||||
|
||||
## [v0.12.2] - 2022-07-09
|
||||
|
||||
## Added
|
||||
|
||||
- Added `Entry` API for `HashSet`. (#342)
|
||||
- Added `Extend<&'a (K, V)> for HashMap<K, V, S, A>`. (#340)
|
||||
- Added length-based short-circuiting for hash table iteration. (#338)
|
||||
- Added a function to access the `RawTable` of a `HashMap`. (#335)
|
||||
|
||||
## Changed
|
||||
|
||||
- Edited `do_alloc` to reduce LLVM IR generated. (#341)
|
||||
|
||||
## [v0.12.1] - 2022-05-02
|
||||
|
||||
## Fixed
|
||||
|
||||
- Fixed underflow in `RawIterRange::size_hint`. (#325)
|
||||
- Fixed the implementation of `Debug` for `ValuesMut` and `IntoValues`. (#325)
|
||||
|
||||
## [v0.12.0] - 2022-01-17
|
||||
|
||||
## Added
|
||||
|
||||
- Added `From<[T; N]>` and `From<[(K, V); N]>` for `HashSet` and `HashMap` respectively. (#297)
|
||||
- Added an `allocator()` getter to HashMap and HashSet. (#257)
|
||||
- Added `insert_unique_unchecked` to `HashMap` and `HashSet`. (#293)
|
||||
- Added `into_keys` and `into_values` to HashMap. (#295)
|
||||
- Implement `From<array>` on `HashSet` and `HashMap`. (#298)
|
||||
- Added `entry_ref` API to `HashMap`. (#201)
|
||||
|
||||
## Changed
|
||||
|
||||
- Bumped minimum Rust version to 1.56.1 and edition to 2021.
|
||||
- Use u64 for the GroupWord on WebAssembly. (#271)
|
||||
- Optimized `find`. (#279)
|
||||
- Made rehashing and resizing less generic to reduce compilation time. (#282)
|
||||
- Inlined small functions. (#283)
|
||||
- Use `BuildHasher::hash_one` when `feature = "nightly"` is enabled. (#292)
|
||||
- Relaxed the bounds on `Debug` for `HashSet`. (#296)
|
||||
- Rename `get_each_mut` to `get_many_mut` and align API with the stdlib. (#291)
|
||||
- Don't hash the key when searching in an empty table. (#305)
|
||||
|
||||
## Fixed
|
||||
|
||||
- Guard against allocations exceeding isize::MAX. (#268)
|
||||
- Made `RawTable::insert_no_grow` unsafe. (#254)
|
||||
- Inline `static_empty`. (#280)
|
||||
- Fixed trait bounds on Send/Sync impls. (#303)
|
||||
|
||||
## [v0.11.2] - 2021-03-25
|
||||
|
||||
## Fixed
|
||||
|
@ -307,7 +363,11 @@ This release was _yanked_ due to a breaking change for users of `no-default-feat
|
|||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...HEAD
|
||||
[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.12.3...HEAD
|
||||
[v0.12.3]: https://github.com/rust-lang/hashbrown/compare/v0.12.2...v0.12.3
|
||||
[v0.12.2]: https://github.com/rust-lang/hashbrown/compare/v0.12.1...v0.12.2
|
||||
[v0.12.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.0...v0.12.1
|
||||
[v0.12.0]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...v0.12.0
|
||||
[v0.11.2]: https://github.com/rust-lang/hashbrown/compare/v0.11.1...v0.11.2
|
||||
[v0.11.1]: https://github.com/rust-lang/hashbrown/compare/v0.11.0...v0.11.1
|
||||
[v0.11.0]: https://github.com/rust-lang/hashbrown/compare/v0.10.0...v0.11.0
|
||||
|
|
|
@ -3,27 +3,46 @@
|
|||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
rust-version = "1.56.0"
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
version = "0.12.3"
|
||||
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
|
||||
exclude = [".travis.yml", "bors.toml", "/ci/*"]
|
||||
exclude = [
|
||||
".github",
|
||||
"/ci/*",
|
||||
]
|
||||
description = "A Rust port of Google's SwissTable hash map"
|
||||
readme = "README.md"
|
||||
keywords = ["hash", "no_std", "hashmap", "swisstable"]
|
||||
categories = ["data-structures", "no-std"]
|
||||
license = "Apache-2.0/MIT"
|
||||
keywords = [
|
||||
"hash",
|
||||
"no_std",
|
||||
"hashmap",
|
||||
"swisstable",
|
||||
]
|
||||
categories = [
|
||||
"data-structures",
|
||||
"no-std",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-lang/hashbrown"
|
||||
resolver = "2"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["nightly", "rayon", "serde", "raw"]
|
||||
features = [
|
||||
"nightly",
|
||||
"rayon",
|
||||
"serde",
|
||||
"raw",
|
||||
]
|
||||
|
||||
[dependencies.ahash]
|
||||
version = "0.7.0"
|
||||
optional = true
|
||||
|
@ -55,6 +74,7 @@ optional = true
|
|||
version = "1.0.25"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.doc-comment]
|
||||
version = "0.3.1"
|
||||
|
||||
|
@ -65,7 +85,7 @@ version = "1.0.7"
|
|||
version = "1.4"
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.7.3"
|
||||
version = "0.8.3"
|
||||
features = ["small_rng"]
|
||||
|
||||
[dev-dependencies.rayon]
|
||||
|
@ -76,9 +96,18 @@ version = "1.0"
|
|||
|
||||
[features]
|
||||
ahash-compile-time-rng = ["ahash/compile-time-rng"]
|
||||
default = ["ahash", "inline-more"]
|
||||
default = [
|
||||
"ahash",
|
||||
"inline-more",
|
||||
]
|
||||
inline-more = []
|
||||
nightly = []
|
||||
raw = []
|
||||
rustc-dep-of-std = ["nightly", "core", "compiler_builtins", "alloc", "rustc-internal-api"]
|
||||
rustc-dep-of-std = [
|
||||
"nightly",
|
||||
"core",
|
||||
"compiler_builtins",
|
||||
"alloc",
|
||||
"rustc-internal-api",
|
||||
]
|
||||
rustc-internal-api = []
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
hashbrown
|
||||
=========
|
||||
|
||||
[![Build Status](https://travis-ci.com/rust-lang/hashbrown.svg?branch=master)](https://travis-ci.com/rust-lang/hashbrown)
|
||||
[![Build Status](https://github.com/rust-lang/hashbrown/actions/workflows/rust.yml/badge.svg)](https://github.com/rust-lang/hashbrown/actions)
|
||||
[![Crates.io](https://img.shields.io/crates/v/hashbrown.svg)](https://crates.io/crates/hashbrown)
|
||||
[![Documentation](https://docs.rs/hashbrown/badge.svg)](https://docs.rs/hashbrown)
|
||||
[![Rust](https://img.shields.io/badge/rust-1.49.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown)
|
||||
[![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown)
|
||||
|
||||
This crate is a Rust port of Google's high-performance [SwissTable] hash
|
||||
map, adapted to make it a drop-in replacement for Rust's standard `HashMap`
|
||||
|
@ -85,7 +85,7 @@ Add this to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
hashbrown = "0.11"
|
||||
hashbrown = "0.12"
|
||||
```
|
||||
|
||||
Then:
|
||||
|
@ -114,8 +114,8 @@ this pre-generates seeds at compile time and embeds them as constants. See [aHas
|
|||
|
||||
Licensed under either of:
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ impl Iterator for RandomKeys {
|
|||
type Item = usize;
|
||||
fn next(&mut self) -> Option<usize> {
|
||||
// Add 1 then multiply by some 32 bit prime.
|
||||
self.state = self.state.wrapping_add(1).wrapping_mul(3787392781);
|
||||
self.state = self.state.wrapping_add(1).wrapping_mul(3_787_392_781);
|
||||
Some(self.state)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
//! Compare `insert` and `insert_unique_unchecked` operations performance.
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn insert(b: &mut Bencher) {
|
||||
let keys: Vec<String> = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect();
|
||||
b.iter(|| {
|
||||
let mut m = HashMap::with_capacity(1000);
|
||||
for k in &keys {
|
||||
m.insert(k, k);
|
||||
}
|
||||
m
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn insert_unique_unchecked(b: &mut Bencher) {
|
||||
let keys: Vec<String> = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect();
|
||||
b.iter(|| {
|
||||
let mut m = HashMap::with_capacity(1000);
|
||||
for k in &keys {
|
||||
m.insert_unique_unchecked(k, k);
|
||||
}
|
||||
m
|
||||
});
|
||||
}
|
|
@ -4,6 +4,7 @@ use alloc::vec::Vec;
|
|||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
/// Helper for collecting parallel iterators to an intermediary
|
||||
#[allow(clippy::linkedlist)] // yes, we need linked list here for efficient appending!
|
||||
pub(super) fn collect<I: IntoParallelIterator>(iter: I) -> (LinkedList<Vec<I::Item>>, usize) {
|
||||
let list = iter
|
||||
.into_par_iter()
|
||||
|
|
|
@ -512,7 +512,7 @@ mod test_par_map {
|
|||
where
|
||||
H: Hasher,
|
||||
{
|
||||
self.k.hash(state)
|
||||
self.k.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -679,7 +679,7 @@ mod test_par_map {
|
|||
fn test_values_mut() {
|
||||
let vec = vec![(1, 1), (2, 2), (3, 3)];
|
||||
let mut map: HashMap<_, _> = vec.into_par_iter().collect();
|
||||
map.par_values_mut().for_each(|value| *value = (*value) * 2);
|
||||
map.par_values_mut().for_each(|value| *value *= 2);
|
||||
let values: Vec<_> = map.par_values().cloned().collect();
|
||||
assert_eq!(values.len(), 3);
|
||||
assert!(values.contains(&2));
|
||||
|
|
|
@ -87,7 +87,7 @@ impl<T, A: Allocator + Clone> RawIntoParIter<T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Clone> ParallelIterator for RawIntoParIter<T, A> {
|
||||
impl<T: Send, A: Allocator + Clone + Send> ParallelIterator for RawIntoParIter<T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
|
@ -116,7 +116,7 @@ pub struct RawParDrain<'a, T, A: Allocator + Clone = Global> {
|
|||
marker: PhantomData<&'a RawTable<T, A>>,
|
||||
}
|
||||
|
||||
unsafe impl<T, A: Allocator + Clone> Send for RawParDrain<'_, T, A> {}
|
||||
unsafe impl<T: Send, A: Allocator + Clone> Send for RawParDrain<'_, T, A> {}
|
||||
|
||||
impl<T, A: Allocator + Clone> RawParDrain<'_, T, A> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
|
@ -134,7 +134,7 @@ impl<T: Send, A: Allocator + Clone> ParallelIterator for RawParDrain<'_, T, A> {
|
|||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
let _guard = guard(self.table, |table| unsafe {
|
||||
table.as_mut().clear_no_drop()
|
||||
table.as_mut().clear_no_drop();
|
||||
});
|
||||
let iter = unsafe { self.table.as_ref().iter().iter };
|
||||
mem::forget(self);
|
||||
|
@ -146,7 +146,9 @@ impl<T: Send, A: Allocator + Clone> ParallelIterator for RawParDrain<'_, T, A> {
|
|||
impl<T, A: Allocator + Clone> Drop for RawParDrain<'_, T, A> {
|
||||
fn drop(&mut self) {
|
||||
// If drive_unindexed is not called then simply clear the table.
|
||||
unsafe { self.table.as_mut().clear() }
|
||||
unsafe {
|
||||
self.table.as_mut().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +177,7 @@ impl<T: Send> UnindexedProducer for ParDrainProducer<T> {
|
|||
{
|
||||
// Make sure to modify the iterator in-place so that any remaining
|
||||
// elements are processed in our Drop impl.
|
||||
while let Some(item) = self.iter.next() {
|
||||
for item in &mut self.iter {
|
||||
folder = folder.consume(unsafe { item.read() });
|
||||
if folder.full() {
|
||||
return folder;
|
||||
|
@ -193,7 +195,7 @@ impl<T> Drop for ParDrainProducer<T> {
|
|||
fn drop(&mut self) {
|
||||
// Drop all remaining elements
|
||||
if mem::needs_drop::<T>() {
|
||||
while let Some(item) = self.iter.next() {
|
||||
for item in &mut self.iter {
|
||||
unsafe {
|
||||
item.drop();
|
||||
}
|
||||
|
|
|
@ -161,6 +161,7 @@ mod set {
|
|||
deserializer.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
allocator_api,
|
||||
slice_ptr_get,
|
||||
nonnull_slice_from_raw_parts,
|
||||
maybe_uninit_array_assume_init
|
||||
maybe_uninit_array_assume_init,
|
||||
build_hasher_simple_hash_one
|
||||
)
|
||||
)]
|
||||
#![allow(
|
||||
|
@ -30,7 +31,9 @@
|
|||
clippy::must_use_candidate,
|
||||
clippy::option_if_let_else,
|
||||
clippy::redundant_else,
|
||||
clippy::manual_map
|
||||
clippy::manual_map,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::missing_errors_doc
|
||||
)]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
@ -128,20 +131,6 @@ pub enum TryReserveError {
|
|||
},
|
||||
}
|
||||
|
||||
/// The error type for [`RawTable::get_each_mut`](crate::raw::RawTable::get_each_mut),
|
||||
/// [`HashMap::get_each_mut`], and [`HashMap::get_each_key_value_mut`].
|
||||
#[cfg(feature = "nightly")]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum UnavailableMutError {
|
||||
/// The requested entry is not present in the table.
|
||||
Absent,
|
||||
/// The requested entry is present, but a mutable reference to it was already created and
|
||||
/// returned from this call to `get_each_mut` or `get_each_key_value_mut`.
|
||||
///
|
||||
/// Includes the index of the existing mutable reference in the returned array.
|
||||
Duplicate(usize),
|
||||
}
|
||||
|
||||
/// Wrapper around `Bump` which allows it to be used as an allocator for
|
||||
/// `HashMap`, `HashSet` and `RawTable`.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// See the cfg-if crate.
|
||||
#[allow(unused_macro_rules)]
|
||||
macro_rules! cfg_if {
|
||||
// match if/else chains with a final `else`
|
||||
($(
|
||||
|
@ -57,8 +58,8 @@ macro_rules! cfg_if {
|
|||
// default fn syntax for specialization changes in the future.
|
||||
#[cfg(feature = "nightly")]
|
||||
macro_rules! default_fn {
|
||||
($($tt:tt)*) => {
|
||||
default $($tt)*
|
||||
(#[$($a:tt)*] $($tt:tt)*) => {
|
||||
#[$($a)*] default $($tt)*
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,10 +8,10 @@ mod inner {
|
|||
|
||||
#[allow(clippy::map_err_ignore)]
|
||||
pub fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> {
|
||||
alloc
|
||||
.allocate(layout)
|
||||
.map(|ptr| ptr.as_non_null_ptr())
|
||||
.map_err(|_| ())
|
||||
match alloc.allocate(layout) {
|
||||
Ok(ptr) => Ok(ptr.as_non_null_ptr()),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bumpalo")]
|
||||
|
@ -33,6 +33,7 @@ mod inner {
|
|||
use crate::alloc::alloc::{alloc, dealloc, Layout};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
#[allow(clippy::missing_safety_doc)] // not exposed outside of this crate
|
||||
pub unsafe trait Allocator {
|
||||
fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()>;
|
||||
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
|
||||
|
@ -47,7 +48,7 @@ mod inner {
|
|||
}
|
||||
#[inline]
|
||||
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
|
||||
dealloc(ptr.as_ptr(), layout)
|
||||
dealloc(ptr.as_ptr(), layout);
|
||||
}
|
||||
}
|
||||
impl Default for Global {
|
||||
|
|
|
@ -106,7 +106,7 @@ impl IntoIterator for BitMask {
|
|||
}
|
||||
}
|
||||
|
||||
/// Iterator over the contents of a `BitMask`, returning the indicies of set
|
||||
/// Iterator over the contents of a `BitMask`, returning the indices of set
|
||||
/// bits.
|
||||
pub struct BitMaskIter(BitMask);
|
||||
|
||||
|
|
|
@ -9,12 +9,14 @@ use core::{mem, ptr};
|
|||
target_pointer_width = "64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "wasm32",
|
||||
))]
|
||||
type GroupWord = u64;
|
||||
#[cfg(all(
|
||||
target_pointer_width = "32",
|
||||
not(target_arch = "aarch64"),
|
||||
not(target_arch = "x86_64"),
|
||||
not(target_arch = "wasm32"),
|
||||
))]
|
||||
type GroupWord = u32;
|
||||
|
||||
|
@ -37,7 +39,7 @@ fn repeat(byte: u8) -> GroupWord {
|
|||
#[derive(Copy, Clone)]
|
||||
pub struct Group(GroupWord);
|
||||
|
||||
// We perform all operations in the native endianess, and convert to
|
||||
// We perform all operations in the native endianness, and convert to
|
||||
// little-endian just before creating a BitMask. The can potentially
|
||||
// enable the compiler to eliminate unnecessary byte swaps if we are
|
||||
// only checking whether a BitMask is empty.
|
||||
|
@ -50,6 +52,7 @@ impl Group {
|
|||
/// value for an empty hash table.
|
||||
///
|
||||
/// This is guaranteed to be aligned to the group size.
|
||||
#[inline]
|
||||
pub const fn static_empty() -> &'static [u8; Group::WIDTH] {
|
||||
#[repr(C)]
|
||||
struct AlignedBytes {
|
||||
|
@ -103,7 +106,7 @@ impl Group {
|
|||
#[inline]
|
||||
pub fn match_byte(self, byte: u8) -> BitMask {
|
||||
// This algorithm is derived from
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
|
||||
let cmp = self.0 ^ repeat(byte);
|
||||
BitMask((cmp.wrapping_sub(repeat(0x01)) & !cmp & repeat(0x80)).to_le())
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -28,6 +28,7 @@ impl Group {
|
|||
/// value for an empty hash table.
|
||||
///
|
||||
/// This is guaranteed to be aligned to the group size.
|
||||
#[inline]
|
||||
#[allow(clippy::items_after_statements)]
|
||||
pub const fn static_empty() -> &'static [u8; Group::WIDTH] {
|
||||
#[repr(C)]
|
||||
|
|
|
@ -56,10 +56,10 @@ where
|
|||
|
||||
/// A view into a single entry in a map, which may either be vacant or occupied.
|
||||
///
|
||||
/// This `enum` is constructed from the [`entry`] method on [`HashMap`].
|
||||
/// This `enum` is constructed from the [`rustc_entry`] method on [`HashMap`].
|
||||
///
|
||||
/// [`HashMap`]: struct.HashMap.html
|
||||
/// [`entry`]: struct.HashMap.html#method.rustc_entry
|
||||
/// [`rustc_entry`]: struct.HashMap.html#method.rustc_entry
|
||||
pub enum RustcEntry<'a, K, V, A = Global>
|
||||
where
|
||||
A: Allocator + Clone,
|
||||
|
@ -145,7 +145,7 @@ impl<'a, K, V, A: Allocator + Clone> RustcEntry<'a, K, V, A> {
|
|||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// let entry = map.entry("horseyland").insert(37);
|
||||
/// let entry = map.rustc_entry("horseyland").insert(37);
|
||||
///
|
||||
/// assert_eq!(entry.key(), &"horseyland");
|
||||
/// ```
|
||||
|
@ -431,10 +431,8 @@ impl<'a, K, V, A: Allocator + Clone> RustcOccupiedEntry<'a, K, V, A> {
|
|||
/// assert_eq!(map["poneyland"], 15);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert(&mut self, mut value: V) -> V {
|
||||
let old_value = self.get_mut();
|
||||
mem::swap(&mut value, old_value);
|
||||
value
|
||||
pub fn insert(&mut self, value: V) -> V {
|
||||
mem::replace(self.get_mut(), value)
|
||||
}
|
||||
|
||||
/// Takes the value out of the entry, and returns it.
|
||||
|
@ -574,8 +572,10 @@ impl<'a, K, V, A: Allocator + Clone> RustcVacantEntry<'a, K, V, A> {
|
|||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert(self, value: V) -> &'a mut V {
|
||||
unsafe {
|
||||
let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
|
||||
unsafe { &mut bucket.as_mut().1 }
|
||||
&mut bucket.as_mut().1
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the RustcVacantEntry's key,
|
||||
|
@ -596,7 +596,7 @@ impl<'a, K, V, A: Allocator + Clone> RustcVacantEntry<'a, K, V, A> {
|
|||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> {
|
||||
let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
|
||||
let bucket = unsafe { self.table.insert_no_grow(self.hash, (self.key, value)) };
|
||||
RustcOccupiedEntry {
|
||||
key: None,
|
||||
elem: bucket,
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// Extracted from the scopeguard crate
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::{
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
ptr,
|
||||
};
|
||||
|
||||
pub struct ScopeGuard<T, F>
|
||||
where
|
||||
|
@ -17,6 +21,27 @@ where
|
|||
ScopeGuard { dropfn, value }
|
||||
}
|
||||
|
||||
impl<T, F> ScopeGuard<T, F>
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
#[inline]
|
||||
pub fn into_inner(guard: Self) -> T {
|
||||
// Cannot move out of Drop-implementing types, so
|
||||
// ptr::read the value and forget the guard.
|
||||
unsafe {
|
||||
let value = ptr::read(&guard.value);
|
||||
// read the closure so that it is dropped, and assign it to a local
|
||||
// variable to ensure that it is only dropped after the guard has
|
||||
// been forgotten. (In case the Drop impl of the closure, or that
|
||||
// of any consumed captured variable, panics).
|
||||
let _dropfn = ptr::read(&guard.dropfn);
|
||||
mem::forget(guard);
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F> Deref for ScopeGuard<T, F>
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
|
@ -44,6 +69,6 @@ where
|
|||
{
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
(self.dropfn)(&mut self.value)
|
||||
(self.dropfn)(&mut self.value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -378,7 +378,7 @@ impl<T, S, A: Allocator + Clone> HashSet<T, S, A> {
|
|||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn clear(&mut self) {
|
||||
self.map.clear()
|
||||
self.map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,6 +454,12 @@ impl<T, S, A> HashSet<T, S, A>
|
|||
where
|
||||
A: Allocator + Clone,
|
||||
{
|
||||
/// Returns a reference to the underlying allocator.
|
||||
#[inline]
|
||||
pub fn allocator(&self) -> &A {
|
||||
self.map.allocator()
|
||||
}
|
||||
|
||||
/// Creates a new empty hash set which will use the given hasher to hash
|
||||
/// keys.
|
||||
///
|
||||
|
@ -553,7 +559,7 @@ where
|
|||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
self.map.reserve(additional)
|
||||
self.map.reserve(additional);
|
||||
}
|
||||
|
||||
/// Tries to reserve capacity for at least `additional` more elements to be inserted
|
||||
|
@ -595,7 +601,7 @@ where
|
|||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
self.map.shrink_to_fit()
|
||||
self.map.shrink_to_fit();
|
||||
}
|
||||
|
||||
/// Shrinks the capacity of the set with a lower limit. It will drop
|
||||
|
@ -621,7 +627,7 @@ where
|
|||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn shrink_to(&mut self, min_capacity: usize) {
|
||||
self.map.shrink_to(min_capacity)
|
||||
self.map.shrink_to(min_capacity);
|
||||
}
|
||||
|
||||
/// Visits the values representing the difference,
|
||||
|
@ -896,6 +902,47 @@ where
|
|||
.0
|
||||
}
|
||||
|
||||
/// Gets the given value's corresponding entry in the set for in-place manipulation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashSet;
|
||||
/// use hashbrown::hash_set::Entry::*;
|
||||
///
|
||||
/// let mut singles = HashSet::new();
|
||||
/// let mut dupes = HashSet::new();
|
||||
///
|
||||
/// for ch in "a short treatise on fungi".chars() {
|
||||
/// if let Vacant(dupe_entry) = dupes.entry(ch) {
|
||||
/// // We haven't already seen a duplicate, so
|
||||
/// // check if we've at least seen it once.
|
||||
/// match singles.entry(ch) {
|
||||
/// Vacant(single_entry) => {
|
||||
/// // We found a new character for the first time.
|
||||
/// single_entry.insert()
|
||||
/// }
|
||||
/// Occupied(single_entry) => {
|
||||
/// // We've already seen this once, "move" it to dupes.
|
||||
/// single_entry.remove();
|
||||
/// dupe_entry.insert();
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert!(!singles.contains(&'t') && dupes.contains(&'t'));
|
||||
/// assert!(singles.contains(&'u') && !dupes.contains(&'u'));
|
||||
/// assert!(!singles.contains(&'v') && !dupes.contains(&'v'));
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn entry(&mut self, value: T) -> Entry<'_, T, S, A> {
|
||||
match self.map.entry(value) {
|
||||
map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }),
|
||||
map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { inner: entry }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` has no elements in common with `other`.
|
||||
/// This is equivalent to checking for an empty intersection.
|
||||
///
|
||||
|
@ -985,6 +1032,30 @@ where
|
|||
self.map.insert(value, ()).is_none()
|
||||
}
|
||||
|
||||
/// Insert a value the set without checking if the value already exists in the set.
|
||||
///
|
||||
/// Returns a reference to the value just inserted.
|
||||
///
|
||||
/// This operation is safe if a value does not exist in the set.
|
||||
///
|
||||
/// However, if a value exists in the set already, the behavior is unspecified:
|
||||
/// this operation may panic, loop forever, or any following operation with the set
|
||||
/// may panic, loop forever or return arbitrary result.
|
||||
///
|
||||
/// That said, this operation (and following operations) are guaranteed to
|
||||
/// not violate memory safety.
|
||||
///
|
||||
/// This operation is faster than regular insert, because it does not perform
|
||||
/// lookup before insertion.
|
||||
///
|
||||
/// This operation is useful during initial population of the set.
|
||||
/// For example, when constructing a set from another set, we know
|
||||
/// that values are unique.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert_unique_unchecked(&mut self, value: T) -> &T {
|
||||
self.map.insert_unique_unchecked(value, ()).0
|
||||
}
|
||||
|
||||
/// Adds a value to the set, replacing the existing value, if any, that is equal to the given
|
||||
/// one. Returns the replaced value.
|
||||
///
|
||||
|
@ -1098,8 +1169,7 @@ where
|
|||
|
||||
impl<T, S, A> fmt::Debug for HashSet<T, S, A>
|
||||
where
|
||||
T: Eq + Hash + fmt::Debug,
|
||||
S: BuildHasher,
|
||||
T: fmt::Debug,
|
||||
A: Allocator + Clone,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -1130,6 +1200,27 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// The default hasher is used to match the std implementation signature
|
||||
#[cfg(feature = "ahash")]
|
||||
impl<T, A, const N: usize> From<[T; N]> for HashSet<T, DefaultHashBuilder, A>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
A: Default + Allocator + Clone,
|
||||
{
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashSet;
|
||||
///
|
||||
/// let set1 = HashSet::from([1, 2, 3, 4]);
|
||||
/// let set2: HashSet<_> = [1, 2, 3, 4].into();
|
||||
/// assert_eq!(set1, set2);
|
||||
/// ```
|
||||
fn from(arr: [T; N]) -> Self {
|
||||
arr.into_iter().collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, A> Extend<T> for HashSet<T, S, A>
|
||||
where
|
||||
T: Eq + Hash,
|
||||
|
@ -1162,7 +1253,7 @@ where
|
|||
{
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
self.extend(iter.into_iter().copied());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -1796,6 +1887,406 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// A view into a single entry in a set, which may either be vacant or occupied.
|
||||
///
|
||||
/// This `enum` is constructed from the [`entry`] method on [`HashSet`].
|
||||
///
|
||||
/// [`HashSet`]: struct.HashSet.html
|
||||
/// [`entry`]: struct.HashSet.html#method.entry
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry};
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// set.extend(["a", "b", "c"]);
|
||||
/// assert_eq!(set.len(), 3);
|
||||
///
|
||||
/// // Existing value (insert)
|
||||
/// let entry: Entry<_, _> = set.entry("a");
|
||||
/// let _raw_o: OccupiedEntry<_, _> = entry.insert();
|
||||
/// assert_eq!(set.len(), 3);
|
||||
/// // Nonexistent value (insert)
|
||||
/// set.entry("d").insert();
|
||||
///
|
||||
/// // Existing value (or_insert)
|
||||
/// set.entry("b").or_insert();
|
||||
/// // Nonexistent value (or_insert)
|
||||
/// set.entry("e").or_insert();
|
||||
///
|
||||
/// println!("Our HashSet: {:?}", set);
|
||||
///
|
||||
/// let mut vec: Vec<_> = set.iter().copied().collect();
|
||||
/// // The `Iter` iterator produces items in arbitrary order, so the
|
||||
/// // items must be sorted to test them against a sorted array.
|
||||
/// vec.sort_unstable();
|
||||
/// assert_eq!(vec, ["a", "b", "c", "d", "e"]);
|
||||
/// ```
|
||||
pub enum Entry<'a, T, S, A = Global>
|
||||
where
|
||||
A: Allocator + Clone,
|
||||
{
|
||||
/// An occupied entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_set::{Entry, HashSet};
|
||||
/// let mut set: HashSet<_> = ["a", "b"].into();
|
||||
///
|
||||
/// match set.entry("a") {
|
||||
/// Entry::Vacant(_) => unreachable!(),
|
||||
/// Entry::Occupied(_) => { }
|
||||
/// }
|
||||
/// ```
|
||||
Occupied(OccupiedEntry<'a, T, S, A>),
|
||||
|
||||
/// A vacant entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_set::{Entry, HashSet};
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
///
|
||||
/// match set.entry("a") {
|
||||
/// Entry::Occupied(_) => unreachable!(),
|
||||
/// Entry::Vacant(_) => { }
|
||||
/// }
|
||||
/// ```
|
||||
Vacant(VacantEntry<'a, T, S, A>),
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, S, A: Allocator + Clone> fmt::Debug for Entry<'_, T, S, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
|
||||
Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A view into an occupied entry in a `HashSet`.
|
||||
/// It is part of the [`Entry`] enum.
|
||||
///
|
||||
/// [`Entry`]: enum.Entry.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry};
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// set.extend(["a", "b", "c"]);
|
||||
///
|
||||
/// let _entry_o: OccupiedEntry<_, _> = set.entry("a").insert();
|
||||
/// assert_eq!(set.len(), 3);
|
||||
///
|
||||
/// // Existing key
|
||||
/// match set.entry("a") {
|
||||
/// Entry::Vacant(_) => unreachable!(),
|
||||
/// Entry::Occupied(view) => {
|
||||
/// assert_eq!(view.get(), &"a");
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(set.len(), 3);
|
||||
///
|
||||
/// // Existing key (take)
|
||||
/// match set.entry("c") {
|
||||
/// Entry::Vacant(_) => unreachable!(),
|
||||
/// Entry::Occupied(view) => {
|
||||
/// assert_eq!(view.remove(), "c");
|
||||
/// }
|
||||
/// }
|
||||
/// assert_eq!(set.get(&"c"), None);
|
||||
/// assert_eq!(set.len(), 2);
|
||||
/// ```
|
||||
pub struct OccupiedEntry<'a, T, S, A: Allocator + Clone = Global> {
|
||||
inner: map::OccupiedEntry<'a, T, (), S, A>,
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, S, A: Allocator + Clone> fmt::Debug for OccupiedEntry<'_, T, S, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OccupiedEntry")
|
||||
.field("value", self.get())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A view into a vacant entry in a `HashSet`.
|
||||
/// It is part of the [`Entry`] enum.
|
||||
///
|
||||
/// [`Entry`]: enum.Entry.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_set::{Entry, HashSet, VacantEntry};
|
||||
///
|
||||
/// let mut set = HashSet::<&str>::new();
|
||||
///
|
||||
/// let entry_v: VacantEntry<_, _> = match set.entry("a") {
|
||||
/// Entry::Vacant(view) => view,
|
||||
/// Entry::Occupied(_) => unreachable!(),
|
||||
/// };
|
||||
/// entry_v.insert();
|
||||
/// assert!(set.contains("a") && set.len() == 1);
|
||||
///
|
||||
/// // Nonexistent key (insert)
|
||||
/// match set.entry("b") {
|
||||
/// Entry::Vacant(view) => view.insert(),
|
||||
/// Entry::Occupied(_) => unreachable!(),
|
||||
/// }
|
||||
/// assert!(set.contains("b") && set.len() == 2);
|
||||
/// ```
|
||||
pub struct VacantEntry<'a, T, S, A: Allocator + Clone = Global> {
|
||||
inner: map::VacantEntry<'a, T, (), S, A>,
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, S, A: Allocator + Clone> fmt::Debug for VacantEntry<'_, T, S, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("VacantEntry").field(self.get()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, S, A: Allocator + Clone> Entry<'a, T, S, A> {
|
||||
/// Sets the value of the entry, and returns an OccupiedEntry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashSet;
|
||||
///
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
/// let entry = set.entry("horseyland").insert();
|
||||
///
|
||||
/// assert_eq!(entry.get(), &"horseyland");
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert(self) -> OccupiedEntry<'a, T, S, A>
|
||||
where
|
||||
T: Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
match self {
|
||||
Entry::Occupied(entry) => entry,
|
||||
Entry::Vacant(entry) => entry.insert_entry(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures a value is in the entry by inserting if it was vacant.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashSet;
|
||||
///
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
///
|
||||
/// // nonexistent key
|
||||
/// set.entry("poneyland").or_insert();
|
||||
/// assert!(set.contains("poneyland"));
|
||||
///
|
||||
/// // existing key
|
||||
/// set.entry("poneyland").or_insert();
|
||||
/// assert!(set.contains("poneyland"));
|
||||
/// assert_eq!(set.len(), 1);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn or_insert(self)
|
||||
where
|
||||
T: Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
if let Entry::Vacant(entry) = self {
|
||||
entry.insert();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to this entry's value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashSet;
|
||||
///
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
/// set.entry("poneyland").or_insert();
|
||||
/// // existing key
|
||||
/// assert_eq!(set.entry("poneyland").get(), &"poneyland");
|
||||
/// // nonexistent key
|
||||
/// assert_eq!(set.entry("horseland").get(), &"horseland");
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn get(&self) -> &T {
|
||||
match *self {
|
||||
Entry::Occupied(ref entry) => entry.get(),
|
||||
Entry::Vacant(ref entry) => entry.get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, A: Allocator + Clone> OccupiedEntry<'_, T, S, A> {
|
||||
/// Gets a reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_set::{Entry, HashSet};
|
||||
///
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
/// set.entry("poneyland").or_insert();
|
||||
///
|
||||
/// match set.entry("poneyland") {
|
||||
/// Entry::Vacant(_) => panic!(),
|
||||
/// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"),
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn get(&self) -> &T {
|
||||
self.inner.key()
|
||||
}
|
||||
|
||||
/// Takes the value out of the entry, and returns it.
|
||||
/// Keeps the allocated memory for reuse.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashSet;
|
||||
/// use hashbrown::hash_set::Entry;
|
||||
///
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
/// // The set is empty
|
||||
/// assert!(set.is_empty() && set.capacity() == 0);
|
||||
///
|
||||
/// set.entry("poneyland").or_insert();
|
||||
/// let capacity_before_remove = set.capacity();
|
||||
///
|
||||
/// if let Entry::Occupied(o) = set.entry("poneyland") {
|
||||
/// assert_eq!(o.remove(), "poneyland");
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(set.contains("poneyland"), false);
|
||||
/// // Now set hold none elements but capacity is equal to the old one
|
||||
/// assert!(set.len() == 0 && set.capacity() == capacity_before_remove);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn remove(self) -> T {
|
||||
self.inner.remove_entry().0
|
||||
}
|
||||
|
||||
/// Replaces the entry, returning the old value. The new value in the hash map will be
|
||||
/// the value used to create this entry.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Will panic if this OccupiedEntry was created through [`Entry::insert`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_set::{Entry, HashSet};
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut set: HashSet<Rc<String>> = HashSet::new();
|
||||
/// let key_one = Rc::new("Stringthing".to_string());
|
||||
/// let key_two = Rc::new("Stringthing".to_string());
|
||||
///
|
||||
/// set.insert(key_one.clone());
|
||||
/// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1);
|
||||
///
|
||||
/// match set.entry(key_two.clone()) {
|
||||
/// Entry::Occupied(entry) => {
|
||||
/// let old_key: Rc<String> = entry.replace();
|
||||
/// assert!(Rc::ptr_eq(&key_one, &old_key));
|
||||
/// }
|
||||
/// Entry::Vacant(_) => panic!(),
|
||||
/// }
|
||||
///
|
||||
/// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2);
|
||||
/// assert!(set.contains(&"Stringthing".to_owned()));
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn replace(self) -> T {
|
||||
self.inner.replace_key()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, S, A: Allocator + Clone> VacantEntry<'a, T, S, A> {
|
||||
/// Gets a reference to the value that would be used when inserting
|
||||
/// through the `VacantEntry`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashSet;
|
||||
///
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
/// assert_eq!(set.entry("poneyland").get(), &"poneyland");
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn get(&self) -> &T {
|
||||
self.inner.key()
|
||||
}
|
||||
|
||||
/// Take ownership of the value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_set::{Entry, HashSet};
|
||||
///
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
///
|
||||
/// match set.entry("poneyland") {
|
||||
/// Entry::Occupied(_) => panic!(),
|
||||
/// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"),
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn into_value(self) -> T {
|
||||
self.inner.into_key()
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the VacantEntry's value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashSet;
|
||||
/// use hashbrown::hash_set::Entry;
|
||||
///
|
||||
/// let mut set: HashSet<&str> = HashSet::new();
|
||||
///
|
||||
/// if let Entry::Vacant(o) = set.entry("poneyland") {
|
||||
/// o.insert();
|
||||
/// }
|
||||
/// assert!(set.contains("poneyland"));
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert(self)
|
||||
where
|
||||
T: Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
self.inner.insert(());
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn insert_entry(self) -> OccupiedEntry<'a, T, S, A>
|
||||
where
|
||||
T: Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
OccupiedEntry {
|
||||
inner: self.inner.insert_entry(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> {
|
||||
|
@ -1963,7 +2454,7 @@ mod test_set {
|
|||
let expected = [3, 5, 11, 77];
|
||||
for x in a.intersection(&b) {
|
||||
assert!(expected.contains(x));
|
||||
i += 1
|
||||
i += 1;
|
||||
}
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
@ -1986,7 +2477,7 @@ mod test_set {
|
|||
let expected = [1, 5, 11];
|
||||
for x in a.difference(&b) {
|
||||
assert!(expected.contains(x));
|
||||
i += 1
|
||||
i += 1;
|
||||
}
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
@ -2012,7 +2503,7 @@ mod test_set {
|
|||
let expected = [-2, 1, 5, 11, 14, 22];
|
||||
for x in a.symmetric_difference(&b) {
|
||||
assert!(expected.contains(x));
|
||||
i += 1
|
||||
i += 1;
|
||||
}
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
@ -2042,7 +2533,7 @@ mod test_set {
|
|||
let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
|
||||
for x in a.union(&b) {
|
||||
assert!(expected.contains(x));
|
||||
i += 1
|
||||
i += 1;
|
||||
}
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
@ -2068,7 +2559,7 @@ mod test_set {
|
|||
fn test_from_iter() {
|
||||
let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
let set: HashSet<_> = xs.iter().cloned().collect();
|
||||
let set: HashSet<_> = xs.iter().copied().collect();
|
||||
|
||||
for x in &xs {
|
||||
assert!(set.contains(x));
|
||||
|
@ -2230,7 +2721,7 @@ mod test_set {
|
|||
#[test]
|
||||
fn test_retain() {
|
||||
let xs = [1, 2, 3, 4, 5, 6];
|
||||
let mut set: HashSet<i32> = xs.iter().cloned().collect();
|
||||
let mut set: HashSet<i32> = xs.iter().copied().collect();
|
||||
set.retain(|&k| k % 2 == 0);
|
||||
assert_eq!(set.len(), 3);
|
||||
assert!(set.contains(&2));
|
||||
|
@ -2272,7 +2763,7 @@ mod test_set {
|
|||
|
||||
const EMPTY_SET: HashSet<u32, MyHasher> = HashSet::with_hasher(MyHasher);
|
||||
|
||||
let mut set = EMPTY_SET.clone();
|
||||
let mut set = EMPTY_SET;
|
||||
set.insert(19);
|
||||
assert!(set.contains(&19));
|
||||
}
|
||||
|
|
|
@ -269,20 +269,20 @@ fn map_seq_par_equivalence_existing_empty_extend_empty() {
|
|||
let mut map_seq = MAP_EXISTING_EMPTY.clone();
|
||||
let mut map_par = MAP_EXISTING_EMPTY.clone();
|
||||
|
||||
map_seq.extend(MAP_EXTENSION_EMPTY.iter().cloned());
|
||||
map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().cloned());
|
||||
map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied());
|
||||
map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied());
|
||||
|
||||
assert_eq3!(map_seq, map_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_existing_empty_extend() {
|
||||
let expected = MAP_EXTENSION.iter().cloned().collect::<HashMap<_, _>>();
|
||||
let expected = MAP_EXTENSION.iter().copied().collect::<HashMap<_, _>>();
|
||||
let mut map_seq = MAP_EXISTING_EMPTY.clone();
|
||||
let mut map_par = MAP_EXISTING_EMPTY.clone();
|
||||
|
||||
map_seq.extend(MAP_EXTENSION.iter().cloned());
|
||||
map_par.par_extend(MAP_EXTENSION.par_iter().cloned());
|
||||
map_seq.extend(MAP_EXTENSION.iter().copied());
|
||||
map_par.par_extend(MAP_EXTENSION.par_iter().copied());
|
||||
|
||||
assert_eq3!(map_seq, map_par, expected);
|
||||
}
|
||||
|
@ -293,8 +293,8 @@ fn map_seq_par_equivalence_existing_extend_empty() {
|
|||
let mut map_seq = MAP_EXISTING.clone();
|
||||
let mut map_par = MAP_EXISTING.clone();
|
||||
|
||||
map_seq.extend(MAP_EXTENSION_EMPTY.iter().cloned());
|
||||
map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().cloned());
|
||||
map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied());
|
||||
map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied());
|
||||
|
||||
assert_eq3!(map_seq, map_par, expected);
|
||||
}
|
||||
|
@ -305,8 +305,8 @@ fn map_seq_par_equivalence_existing_extend() {
|
|||
let mut map_seq = MAP_EXISTING.clone();
|
||||
let mut map_par = MAP_EXISTING.clone();
|
||||
|
||||
map_seq.extend(MAP_EXTENSION.iter().cloned());
|
||||
map_par.par_extend(MAP_EXTENSION.par_iter().cloned());
|
||||
map_seq.extend(MAP_EXTENSION.iter().copied());
|
||||
map_par.par_extend(MAP_EXTENSION.par_iter().copied());
|
||||
|
||||
assert_eq3!(map_seq, map_par, expected);
|
||||
}
|
||||
|
@ -423,20 +423,20 @@ fn set_seq_par_equivalence_existing_empty_extend_empty() {
|
|||
let mut set_seq = SET_EXISTING_EMPTY.clone();
|
||||
let mut set_par = SET_EXISTING_EMPTY.clone();
|
||||
|
||||
set_seq.extend(SET_EXTENSION_EMPTY.iter().cloned());
|
||||
set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().cloned());
|
||||
set_seq.extend(SET_EXTENSION_EMPTY.iter().copied());
|
||||
set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied());
|
||||
|
||||
assert_eq3!(set_seq, set_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_existing_empty_extend() {
|
||||
let expected = SET_EXTENSION.iter().cloned().collect::<HashSet<_>>();
|
||||
let expected = SET_EXTENSION.iter().copied().collect::<HashSet<_>>();
|
||||
let mut set_seq = SET_EXISTING_EMPTY.clone();
|
||||
let mut set_par = SET_EXISTING_EMPTY.clone();
|
||||
|
||||
set_seq.extend(SET_EXTENSION.iter().cloned());
|
||||
set_par.par_extend(SET_EXTENSION.par_iter().cloned());
|
||||
set_seq.extend(SET_EXTENSION.iter().copied());
|
||||
set_par.par_extend(SET_EXTENSION.par_iter().copied());
|
||||
|
||||
assert_eq3!(set_seq, set_par, expected);
|
||||
}
|
||||
|
@ -447,8 +447,8 @@ fn set_seq_par_equivalence_existing_extend_empty() {
|
|||
let mut set_seq = SET_EXISTING.clone();
|
||||
let mut set_par = SET_EXISTING.clone();
|
||||
|
||||
set_seq.extend(SET_EXTENSION_EMPTY.iter().cloned());
|
||||
set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().cloned());
|
||||
set_seq.extend(SET_EXTENSION_EMPTY.iter().copied());
|
||||
set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied());
|
||||
|
||||
assert_eq3!(set_seq, set_par, expected);
|
||||
}
|
||||
|
@ -459,37 +459,37 @@ fn set_seq_par_equivalence_existing_extend() {
|
|||
let mut set_seq = SET_EXISTING.clone();
|
||||
let mut set_par = SET_EXISTING.clone();
|
||||
|
||||
set_seq.extend(SET_EXTENSION.iter().cloned());
|
||||
set_par.par_extend(SET_EXTENSION.par_iter().cloned());
|
||||
set_seq.extend(SET_EXTENSION.iter().copied());
|
||||
set_par.par_extend(SET_EXTENSION.par_iter().copied());
|
||||
|
||||
assert_eq3!(set_seq, set_par, expected);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SET_A: HashSet<char> = ['a', 'b', 'c', 'd'].iter().cloned().collect();
|
||||
static ref SET_B: HashSet<char> = ['a', 'b', 'e', 'f'].iter().cloned().collect();
|
||||
static ref SET_DIFF_AB: HashSet<char> = ['c', 'd'].iter().cloned().collect();
|
||||
static ref SET_DIFF_BA: HashSet<char> = ['e', 'f'].iter().cloned().collect();
|
||||
static ref SET_SYMM_DIFF_AB: HashSet<char> = ['c', 'd', 'e', 'f'].iter().cloned().collect();
|
||||
static ref SET_INTERSECTION_AB: HashSet<char> = ['a', 'b'].iter().cloned().collect();
|
||||
static ref SET_A: HashSet<char> = ['a', 'b', 'c', 'd'].iter().copied().collect();
|
||||
static ref SET_B: HashSet<char> = ['a', 'b', 'e', 'f'].iter().copied().collect();
|
||||
static ref SET_DIFF_AB: HashSet<char> = ['c', 'd'].iter().copied().collect();
|
||||
static ref SET_DIFF_BA: HashSet<char> = ['e', 'f'].iter().copied().collect();
|
||||
static ref SET_SYMM_DIFF_AB: HashSet<char> = ['c', 'd', 'e', 'f'].iter().copied().collect();
|
||||
static ref SET_INTERSECTION_AB: HashSet<char> = ['a', 'b'].iter().copied().collect();
|
||||
static ref SET_UNION_AB: HashSet<char> =
|
||||
['a', 'b', 'c', 'd', 'e', 'f'].iter().cloned().collect();
|
||||
['a', 'b', 'c', 'd', 'e', 'f'].iter().copied().collect();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_difference() {
|
||||
let diff_ab_seq = SET_A.difference(&*SET_B).cloned().collect::<HashSet<_>>();
|
||||
let diff_ab_seq = SET_A.difference(&*SET_B).copied().collect::<HashSet<_>>();
|
||||
let diff_ab_par = SET_A
|
||||
.par_difference(&*SET_B)
|
||||
.cloned()
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(diff_ab_seq, diff_ab_par, *SET_DIFF_AB);
|
||||
|
||||
let diff_ba_seq = SET_B.difference(&*SET_A).cloned().collect::<HashSet<_>>();
|
||||
let diff_ba_seq = SET_B.difference(&*SET_A).copied().collect::<HashSet<_>>();
|
||||
let diff_ba_par = SET_B
|
||||
.par_difference(&*SET_A)
|
||||
.cloned()
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(diff_ba_seq, diff_ba_par, *SET_DIFF_BA);
|
||||
|
@ -499,11 +499,11 @@ fn set_seq_par_equivalence_difference() {
|
|||
fn set_seq_par_equivalence_symmetric_difference() {
|
||||
let symm_diff_ab_seq = SET_A
|
||||
.symmetric_difference(&*SET_B)
|
||||
.cloned()
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
let symm_diff_ab_par = SET_A
|
||||
.par_symmetric_difference(&*SET_B)
|
||||
.cloned()
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(symm_diff_ab_seq, symm_diff_ab_par, *SET_SYMM_DIFF_AB);
|
||||
|
@ -511,10 +511,10 @@ fn set_seq_par_equivalence_symmetric_difference() {
|
|||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_intersection() {
|
||||
let intersection_ab_seq = SET_A.intersection(&*SET_B).cloned().collect::<HashSet<_>>();
|
||||
let intersection_ab_seq = SET_A.intersection(&*SET_B).copied().collect::<HashSet<_>>();
|
||||
let intersection_ab_par = SET_A
|
||||
.par_intersection(&*SET_B)
|
||||
.cloned()
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(
|
||||
|
@ -526,8 +526,8 @@ fn set_seq_par_equivalence_intersection() {
|
|||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_union() {
|
||||
let union_ab_seq = SET_A.union(&*SET_B).cloned().collect::<HashSet<_>>();
|
||||
let union_ab_par = SET_A.par_union(&*SET_B).cloned().collect::<HashSet<_>>();
|
||||
let union_ab_seq = SET_A.union(&*SET_B).copied().collect::<HashSet<_>>();
|
||||
let union_ab_par = SET_A.par_union(&*SET_B).copied().collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(union_ab_seq, union_ab_par, *SET_UNION_AB);
|
||||
}
|
||||
|
|
|
@ -2,29 +2,33 @@
|
|||
|
||||
use hashbrown::HashSet;
|
||||
use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng};
|
||||
use std::iter;
|
||||
|
||||
#[test]
|
||||
fn test_hashset_insert_remove() {
|
||||
let mut m: HashSet<Vec<char>> = HashSet::new();
|
||||
//let num: u32 = 4096;
|
||||
//let tx: Vec<Vec<u8>> = (0..num).map(|i| (i..(16 + i)).collect()).collect();
|
||||
let seed: [u8; 16] = [
|
||||
130, 220, 246, 217, 111, 124, 221, 189, 190, 234, 121, 93, 67, 95, 100, 43,
|
||||
];
|
||||
let seed = u64::from_le_bytes(*b"testseed");
|
||||
|
||||
let rng = &mut SmallRng::from_seed(seed);
|
||||
let tx: Vec<Vec<char>> = (0..4096)
|
||||
.map(|_| (rng.sample_iter(&Alphanumeric).take(32).collect()))
|
||||
let rng = &mut SmallRng::seed_from_u64(seed);
|
||||
let tx: Vec<Vec<char>> = iter::repeat_with(|| {
|
||||
rng.sample_iter(&Alphanumeric)
|
||||
.take(32)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
})
|
||||
.take(4096)
|
||||
.collect();
|
||||
|
||||
// more readable with explicit `true` / `false`
|
||||
#[allow(clippy::bool_assert_comparison)]
|
||||
for _ in 0..32 {
|
||||
for i in 0..4096 {
|
||||
assert_eq!(m.contains(&tx[i].clone()), false);
|
||||
assert_eq!(m.insert(tx[i].clone()), true);
|
||||
for x in &tx {
|
||||
assert_eq!(m.contains(x), false);
|
||||
assert_eq!(m.insert(x.clone()), true);
|
||||
}
|
||||
for i in 0..4096 {
|
||||
println!("removing {} {:?}", i, tx[i]);
|
||||
assert_eq!(m.remove(&tx[i]), true);
|
||||
for (i, x) in tx.iter().enumerate() {
|
||||
println!("removing {} {:?}", i, x);
|
||||
assert_eq!(m.remove(x), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче