From 61bb73ed5d5b6c092a7ffe43f193db38497c1df2 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 10:59:30 -0800 Subject: [PATCH 01/16] Prepare for indexmap 2.0.0 --- .github/workflows/ci.yml | 4 ++-- .rustfmt.toml | 2 +- Cargo.toml | 29 +++++++---------------------- README.rst | 4 ++-- src/lib.rs | 6 +++--- test-nostd/Cargo.toml | 3 +-- test-serde/Cargo.toml | 3 +-- 7 files changed, 17 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79cc3d8a..739d52cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: include: - - rust: 1.49.0 # MSRV + - rust: 1.56.0 # MSRV features: - rust: stable features: serde @@ -59,7 +59,7 @@ jobs: strategy: matrix: include: - - rust: 1.49.0 + - rust: 1.56.0 target: thumbv6m-none-eabi - rust: stable target: thumbv6m-none-eabi diff --git a/.rustfmt.toml b/.rustfmt.toml index 32a9786f..3a26366d 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1 +1 @@ -edition = "2018" +edition = "2021" diff --git a/Cargo.toml b/Cargo.toml index e330b13f..adcd51a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,37 +1,22 @@ [package] name = "indexmap" -edition = "2018" -version = "1.8.1" -authors = [ -"bluss", -"Josh Stone " -] +edition = "2021" +version = "2.0.0-pre" +publish = false documentation = "https://docs.rs/indexmap/" repository = "https://github.com/bluss/indexmap" -license = "Apache-2.0/MIT" -description = """ -A hash table with consistent order and fast iteration. - -The indexmap is a hash table where the iteration order of the key-value -pairs is independent of the hash values of the keys. It has the usual -hash table functionality, it preserves insertion order except after -removals, and it allows lookup of its elements by either hash table key -or numerical index. A corresponding hash set type is also provided. - -This crate was initially published under the name ordermap, but it was renamed to -indexmap. -""" - +license = "Apache-2.0 OR MIT" +description = "A hash table with consistent order and fast iteration." keywords = ["hashmap", "no_std"] categories = ["data-structures", "no-std"] - -build = "build.rs" +rust-version = "1.56" [lib] bench = false [build-dependencies] autocfg = "1" + [dependencies] serde = { version = "1.0", optional = true, default-features = false } rayon = { version = "1.4.1", optional = true } diff --git a/README.rst b/README.rst index da76a68b..4dac24f4 100644 --- a/README.rst +++ b/README.rst @@ -12,8 +12,8 @@ indexmap .. |docs| image:: https://docs.rs/indexmap/badge.svg .. _docs: https://docs.rs/indexmap -.. |rustc| image:: https://img.shields.io/badge/rust-1.49%2B-orange.svg -.. _rustc: https://img.shields.io/badge/rust-1.49%2B-orange.svg +.. |rustc| image:: https://img.shields.io/badge/rust-1.56%2B-orange.svg +.. _rustc: https://img.shields.io/badge/rust-1.56%2B-orange.svg A pure-Rust hash table which preserves (in a limited sense) insertion order. diff --git a/src/lib.rs b/src/lib.rs index 8c44d7bf..2ef1fb9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,10 +53,10 @@ //! //! ### Rust Version //! -//! This version of indexmap requires Rust 1.49 or later. +//! This version of indexmap requires Rust 1.56 or later. //! -//! The indexmap 1.x release series will use a carefully considered version -//! upgrade policy, where in a later 1.x version, we will raise the minimum +//! The indexmap 2.x release series will use a carefully considered version +//! upgrade policy, where in a later 2.x version, we will raise the minimum //! required Rust version. //! //! ## No Standard Library Targets diff --git a/test-nostd/Cargo.toml b/test-nostd/Cargo.toml index 0201a728..3ae606d5 100644 --- a/test-nostd/Cargo.toml +++ b/test-nostd/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "test-nostd" version = "0.1.0" -authors = ["bluss"] publish = false -edition = "2018" +edition = "2021" [dependencies] indexmap = { path = "..", features = ["serde-1"] } diff --git a/test-serde/Cargo.toml b/test-serde/Cargo.toml index f7abc9e5..791c0a38 100644 --- a/test-serde/Cargo.toml +++ b/test-serde/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "test-serde" version = "0.1.0" -authors = ["bluss"] publish = false -edition = "2018" +edition = "2021" [dependencies] From c3d7c396b6da6fe04f5607924998bd2a6e3435a1 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 11:04:22 -0800 Subject: [PATCH 02/16] Remove unused feature test_low_transition_point --- .github/workflows/ci.yml | 2 -- Cargo.toml | 1 - 2 files changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 739d52cf..f04cce5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,8 +30,6 @@ jobs: features: - rust: nightly bench: test build benchmarks - - rust: nightly - features: test_low_transition_point steps: - uses: actions/checkout@v2 diff --git a/Cargo.toml b/Cargo.toml index adcd51a9..ce260949 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,6 @@ serde-1 = ["serde"] std = [] # for testing only, of course -test_low_transition_point = [] test_debug = [] [profile.bench] From ed9bf13aaf7c46e7ef3332009c0f591fec667e72 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 11:09:58 -0800 Subject: [PATCH 03/16] Remove redundant feature serde-1 --- Cargo.toml | 5 +---- src/serde.rs | 8 ++++---- src/serde_seq.rs | 6 +++--- test-nostd/Cargo.toml | 2 +- test-serde/Cargo.toml | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ce260949..dec5b01e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,9 +40,6 @@ fxhash = "0.2.1" serde_derive = "1.0" [features] -# Serialization with serde 1.0 -serde-1 = ["serde"] - # Force the use of `std`, bypassing target detection. std = [] @@ -57,7 +54,7 @@ no-dev-version = true tag-name = "{{version}}" [package.metadata.docs.rs] -features = ["serde-1", "rayon"] +features = ["serde", "rayon"] [workspace] members = ["test-nostd", "test-serde"] diff --git a/src/serde.rs b/src/serde.rs index c6dd6d5e..d7473d39 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -10,7 +10,7 @@ use core::marker::PhantomData; use crate::IndexMap; -/// Requires crate feature `"serde"` or `"serde-1"` +/// Requires crate feature `"serde"` impl Serialize for IndexMap where K: Serialize + Hash + Eq, @@ -54,7 +54,7 @@ where } } -/// Requires crate feature `"serde"` or `"serde-1"` +/// Requires crate feature `"serde"` impl<'de, K, V, S> Deserialize<'de> for IndexMap where K: Deserialize<'de> + Eq + Hash, @@ -85,7 +85,7 @@ where use crate::IndexSet; -/// Requires crate feature `"serde"` or `"serde-1"` +/// Requires crate feature `"serde"` impl Serialize for IndexSet where T: Serialize + Hash + Eq, @@ -127,7 +127,7 @@ where } } -/// Requires crate feature `"serde"` or `"serde-1"` +/// Requires crate feature `"serde"` impl<'de, T, S> Deserialize<'de> for IndexSet where T: Deserialize<'de> + Eq + Hash, diff --git a/src/serde_seq.rs b/src/serde_seq.rs index d326a02e..7c89a6e5 100644 --- a/src/serde_seq.rs +++ b/src/serde_seq.rs @@ -18,7 +18,7 @@ //! } //! ``` //! -//! Requires crate feature `"serde"` or `"serde-1"` +//! Requires crate feature `"serde"` use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use serde::ser::{Serialize, Serializer}; @@ -44,7 +44,7 @@ use crate::IndexMap; /// } /// ``` /// -/// Requires crate feature `"serde"` or `"serde-1"` +/// Requires crate feature `"serde"` pub fn serialize(map: &IndexMap, serializer: T) -> Result where K: Serialize + Hash + Eq, @@ -100,7 +100,7 @@ where /// } /// ``` /// -/// Requires crate feature `"serde"` or `"serde-1"` +/// Requires crate feature `"serde"` pub fn deserialize<'de, D, K, V, S>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, diff --git a/test-nostd/Cargo.toml b/test-nostd/Cargo.toml index 3ae606d5..e926762d 100644 --- a/test-nostd/Cargo.toml +++ b/test-nostd/Cargo.toml @@ -5,6 +5,6 @@ publish = false edition = "2021" [dependencies] -indexmap = { path = "..", features = ["serde-1"] } +indexmap = { path = "..", features = ["serde"] } [dev-dependencies] diff --git a/test-serde/Cargo.toml b/test-serde/Cargo.toml index 791c0a38..bf04c9fa 100644 --- a/test-serde/Cargo.toml +++ b/test-serde/Cargo.toml @@ -8,6 +8,6 @@ edition = "2021" [dev-dependencies] fnv = "1.0" -indexmap = { path = "..", features = ["serde-1"] } +indexmap = { path = "..", features = ["serde"] } serde = { version = "1.0.99", features = ["derive"] } serde_test = "1.0.99" From 99848fff179911f2573011dfc2859c182c9c0cfb Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 11:19:17 -0800 Subject: [PATCH 04/16] Always use an explicit feature for std --- Cargo.toml | 5 +---- build.rs | 9 --------- src/lib.rs | 11 +++++------ src/macros.rs | 4 ++-- src/map.rs | 12 ++++++------ src/set.rs | 12 ++++++------ test-nostd/Cargo.toml | 6 ++++-- 7 files changed, 24 insertions(+), 35 deletions(-) delete mode 100644 build.rs diff --git a/Cargo.toml b/Cargo.toml index dec5b01e..f5ed534d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,9 +14,6 @@ rust-version = "1.56" [lib] bench = false -[build-dependencies] -autocfg = "1" - [dependencies] serde = { version = "1.0", optional = true, default-features = false } rayon = { version = "1.4.1", optional = true } @@ -40,7 +37,7 @@ fxhash = "0.2.1" serde_derive = "1.0" [features] -# Force the use of `std`, bypassing target detection. +default = ["std"] std = [] # for testing only, of course diff --git a/build.rs b/build.rs deleted file mode 100644 index 7c5b6d5e..00000000 --- a/build.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - // If "std" is explicitly requested, don't bother probing the target for it. - match std::env::var_os("CARGO_FEATURE_STD") { - Some(_) => autocfg::emit("has_std"), - None => autocfg::new().emit_sysroot_crate("std"), - } - autocfg::new().emit_rustc_version(1, 51); - autocfg::rerun_path("build.rs"); -} diff --git a/src/lib.rs b/src/lib.rs index 2ef1fb9f..3d796ea7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,13 +61,12 @@ //! //! ## No Standard Library Targets //! -//! This crate supports being built without `std`, requiring -//! `alloc` instead. This is enabled automatically when it is detected that -//! `std` is not available. There is no crate feature to enable/disable to -//! trigger this. It can be tested by building for a std-less target. +//! This crate supports being built without `std`, requiring `alloc` instead. +//! This is chosen by disabling the default "std" cargo feature, by adding +//! `default-features = false` to your dependency specification. //! //! - Creating maps and sets using [`new`][IndexMap::new] and -//! [`with_capacity`][IndexMap::with_capacity] is unavailable without `std`. +//! [`with_capacity`][IndexMap::with_capacity] is unavailable without `std`. //! Use methods [`IndexMap::default`][def], //! [`with_hasher`][IndexMap::with_hasher], //! [`with_capacity_and_hasher`][IndexMap::with_capacity_and_hasher] instead. @@ -79,7 +78,7 @@ extern crate alloc; -#[cfg(has_std)] +#[cfg(feature = "std")] #[macro_use] extern crate std; diff --git a/src/macros.rs b/src/macros.rs index ca26287b..20ab58db 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,4 +1,4 @@ -#[cfg(has_std)] +#[cfg(feature = "std")] #[macro_export] /// Create an `IndexMap` from a list of key-value pairs /// @@ -35,7 +35,7 @@ macro_rules! indexmap { }; } -#[cfg(has_std)] +#[cfg(feature = "std")] #[macro_export] /// Create an `IndexSet` from a list of values /// diff --git a/src/map.rs b/src/map.rs index 56330470..01bdeb3e 100644 --- a/src/map.rs +++ b/src/map.rs @@ -16,7 +16,7 @@ use ::core::iter::{FromIterator, FusedIterator}; use ::core::ops::{Index, IndexMut, RangeBounds}; use ::core::slice::{Iter as SliceIter, IterMut as SliceIterMut}; -#[cfg(has_std)] +#[cfg(feature = "std")] use std::collections::hash_map::RandomState; use self::core::IndexMapCore; @@ -67,12 +67,12 @@ pub use self::core::{Entry, OccupiedEntry, VacantEntry}; /// assert_eq!(letters[&'u'], 1); /// assert_eq!(letters.get(&'y'), None); /// ``` -#[cfg(has_std)] +#[cfg(feature = "std")] pub struct IndexMap { pub(crate) core: IndexMapCore, hash_builder: S, } -#[cfg(not(has_std))] +#[cfg(not(feature = "std"))] pub struct IndexMap { pub(crate) core: IndexMapCore, hash_builder: S, @@ -140,7 +140,7 @@ where } } -#[cfg(has_std)] +#[cfg(feature = "std")] impl IndexMap { /// Create a new map. (Does not allocate.) #[inline] @@ -1391,7 +1391,7 @@ where } } -#[cfg(all(has_std, rustc_1_51))] +#[cfg(feature = "std")] impl From<[(K, V); N]> for IndexMap where K: Hash + Eq, @@ -1906,7 +1906,7 @@ mod tests { } #[test] - #[cfg(all(has_std, rustc_1_51))] + #[cfg(feature = "std")] fn from_array() { let map = IndexMap::from([(1, 2), (3, 4)]); let mut expected = IndexMap::new(); diff --git a/src/set.rs b/src/set.rs index e82a8d07..02253ce3 100644 --- a/src/set.rs +++ b/src/set.rs @@ -3,7 +3,7 @@ #[cfg(feature = "rayon")] pub use crate::rayon::set as rayon; -#[cfg(has_std)] +#[cfg(feature = "std")] use std::collections::hash_map::RandomState; use crate::vec::{self, Vec}; @@ -59,11 +59,11 @@ type Bucket = super::Bucket; /// assert!(letters.contains(&'u')); /// assert!(!letters.contains(&'y')); /// ``` -#[cfg(has_std)] +#[cfg(feature = "std")] pub struct IndexSet { pub(crate) map: IndexMap, } -#[cfg(not(has_std))] +#[cfg(not(feature = "std"))] pub struct IndexSet { pub(crate) map: IndexMap, } @@ -124,7 +124,7 @@ where } } -#[cfg(has_std)] +#[cfg(feature = "std")] impl IndexSet { /// Create a new set. (Does not allocate.) pub fn new() -> Self { @@ -888,7 +888,7 @@ where } } -#[cfg(all(has_std, rustc_1_51))] +#[cfg(feature = "std")] impl From<[T; N]> for IndexSet where T: Eq + Hash, @@ -1882,7 +1882,7 @@ mod tests { } #[test] - #[cfg(all(has_std, rustc_1_51))] + #[cfg(feature = "std")] fn from_array() { let set1 = IndexSet::from([1, 2, 3, 4]); let set2: IndexSet<_> = [1, 2, 3, 4].into(); diff --git a/test-nostd/Cargo.toml b/test-nostd/Cargo.toml index e926762d..64d209a9 100644 --- a/test-nostd/Cargo.toml +++ b/test-nostd/Cargo.toml @@ -4,7 +4,9 @@ version = "0.1.0" publish = false edition = "2021" -[dependencies] -indexmap = { path = "..", features = ["serde"] } +[dependencies.indexmap] +path = ".." +default-features = false +features = ["serde"] [dev-dependencies] From ffd875b1c03e54299948f2c015965c679ca8737e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 11:22:43 -0800 Subject: [PATCH 05/16] Use prelude FromIterator --- benches/bench.rs | 1 - benches/faststring.rs | 1 - src/map.rs | 4 ++-- src/set.rs | 4 ++-- test-nostd/src/lib.rs | 1 - tests/quick.rs | 1 - 6 files changed, 4 insertions(+), 8 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index d6de602d..a4e8e21b 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -15,7 +15,6 @@ use test::Bencher; use indexmap::IndexMap; use std::collections::HashMap; -use std::iter::FromIterator; use rand::rngs::SmallRng; use rand::seq::SliceRandom; diff --git a/benches/faststring.rs b/benches/faststring.rs index 86b7e9cf..ecc28b40 100644 --- a/benches/faststring.rs +++ b/benches/faststring.rs @@ -7,7 +7,6 @@ use test::Bencher; use indexmap::IndexMap; use std::collections::HashMap; -use std::iter::FromIterator; use rand::rngs::SmallRng; use rand::seq::SliceRandom; diff --git a/src/map.rs b/src/map.rs index 01bdeb3e..62346ba9 100644 --- a/src/map.rs +++ b/src/map.rs @@ -12,7 +12,7 @@ use crate::vec::{self, Vec}; use ::core::cmp::Ordering; use ::core::fmt; use ::core::hash::{BuildHasher, Hash, Hasher}; -use ::core::iter::{FromIterator, FusedIterator}; +use ::core::iter::FusedIterator; use ::core::ops::{Index, IndexMut, RangeBounds}; use ::core::slice::{Iter as SliceIter, IterMut as SliceIterMut}; @@ -1406,7 +1406,7 @@ where /// assert_eq!(map1, map2); /// ``` fn from(arr: [(K, V); N]) -> Self { - std::array::IntoIter::new(arr).collect() + Self::from_iter(arr) } } diff --git a/src/set.rs b/src/set.rs index 02253ce3..cff168c8 100644 --- a/src/set.rs +++ b/src/set.rs @@ -10,7 +10,7 @@ use crate::vec::{self, Vec}; use core::cmp::Ordering; use core::fmt; use core::hash::{BuildHasher, Hash}; -use core::iter::{Chain, FromIterator, FusedIterator}; +use core::iter::{Chain, FusedIterator}; use core::ops::{BitAnd, BitOr, BitXor, Index, RangeBounds, Sub}; use core::slice; @@ -903,7 +903,7 @@ where /// assert_eq!(set1, set2); /// ``` fn from(arr: [T; N]) -> Self { - std::array::IntoIter::new(arr).collect() + Self::from_iter(arr) } } diff --git a/test-nostd/src/lib.rs b/test-nostd/src/lib.rs index 0b57b092..27bfe608 100644 --- a/test-nostd/src/lib.rs +++ b/test-nostd/src/lib.rs @@ -2,7 +2,6 @@ use core::hash::BuildHasherDefault; use core::hash::Hasher; -use core::iter::FromIterator; use indexmap::IndexMap; use indexmap::IndexSet; diff --git a/tests/quick.rs b/tests/quick.rs index 6c6cc034..4f462878 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -16,7 +16,6 @@ use std::collections::HashMap; use std::collections::HashSet; use std::fmt::Debug; use std::hash::Hash; -use std::iter::FromIterator; use std::ops::Bound; use std::ops::Deref; From 8eeea2ce0cbbfb52bc1c1ac9acfab26336e500e0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 12:06:55 -0800 Subject: [PATCH 06/16] Upgrade to hashbrown 0.12 --- Cargo.toml | 2 +- src/map/core.rs | 24 ++++++------------------ src/map/core/raw.rs | 15 ++++++++++++++- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f5ed534d..85867a1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ rayon = { version = "1.4.1", optional = true } rustc-rayon = { version = "0.3", optional = true } [dependencies.hashbrown] -version = "0.11" +version = "0.12" default-features = false features = ["raw"] diff --git a/src/map/core.rs b/src/map/core.rs index bfd571d9..0ed9b1ff 100644 --- a/src/map/core.rs +++ b/src/map/core.rs @@ -18,7 +18,7 @@ use core::mem::replace; use core::ops::RangeBounds; use crate::equivalent::Equivalent; -use crate::util::{enumerate, simplify_range}; +use crate::util::simplify_range; use crate::{Bucket, Entries, HashValue}; /// Core of the map that does not depend on S @@ -185,9 +185,7 @@ impl IndexMapCore { let entries = self.entries.split_off(at); let mut indices = RawTable::with_capacity(entries.len()); - for (i, entry) in enumerate(&entries) { - indices.insert_no_grow(entry.hash.get(), i); - } + raw::insert_bulk_no_grow(&mut indices, &entries); Self { indices, entries } } @@ -372,15 +370,9 @@ impl IndexMapCore { // Reinsert everything, as there are few kept indices self.indices.clear(); - // Reinsert stable indices - for (i, entry) in enumerate(start_entries) { - self.indices.insert_no_grow(entry.hash.get(), i); - } - - // Reinsert shifted indices - for (i, entry) in (start..).zip(shifted_entries) { - self.indices.insert_no_grow(entry.hash.get(), i); - } + // Reinsert stable indices, then shifted indices + raw::insert_bulk_no_grow(&mut self.indices, start_entries); + raw::insert_bulk_no_grow(&mut self.indices, shifted_entries); } else if erased + shifted < half_capacity { // Find each affected index, as there are few to adjust @@ -429,11 +421,7 @@ impl IndexMapCore { fn rebuild_hash_table(&mut self) { self.indices.clear(); - debug_assert!(self.indices.capacity() >= self.entries.len()); - for (i, entry) in enumerate(&self.entries) { - // We should never have to reallocate, so there's no need for a real hasher. - self.indices.insert_no_grow(entry.hash.get(), i); - } + raw::insert_bulk_no_grow(&mut self.indices, &self.entries); } pub(crate) fn reverse(&mut self) { diff --git a/src/map/core/raw.rs b/src/map/core/raw.rs index 168e1af3..bf1672d5 100644 --- a/src/map/core/raw.rs +++ b/src/map/core/raw.rs @@ -2,13 +2,26 @@ //! This module encapsulates the `unsafe` access to `hashbrown::raw::RawTable`, //! mostly in dealing with its bucket "pointers". -use super::{equivalent, Entry, HashValue, IndexMapCore, VacantEntry}; +use super::{equivalent, Bucket, Entry, HashValue, IndexMapCore, VacantEntry}; use core::fmt; use core::mem::replace; use hashbrown::raw::RawTable; type RawBucket = hashbrown::raw::Bucket; +/// Inserts many entries into a raw table without reallocating. +/// +/// ***Panics*** if there is not sufficient capacity already. +pub(super) fn insert_bulk_no_grow(indices: &mut RawTable, entries: &[Bucket]) { + assert!(indices.capacity() - indices.len() >= entries.len()); + for entry in entries { + // SAFETY: we asserted that sufficient capacity exists for all entries. + unsafe { + indices.insert_no_grow(entry.hash.get(), indices.len()); + } + } +} + pub(super) struct DebugIndices<'a>(pub &'a RawTable); impl fmt::Debug for DebugIndices<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From bdd93a379955a250c4629e86cc46ec2ae2848ebf Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 12:07:08 -0800 Subject: [PATCH 07/16] Remove crate::util::enumerate --- src/map.rs | 7 +++---- src/set.rs | 11 +++++------ src/util.rs | 8 -------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/map.rs b/src/map.rs index 62346ba9..932a3b2d 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1495,7 +1495,6 @@ where #[cfg(test)] mod tests { use super::*; - use crate::util::enumerate; use std::string::String; #[test] @@ -1524,7 +1523,7 @@ mod tests { let not_present = [1, 3, 6, 9, 10]; let mut map = IndexMap::with_capacity(insert.len()); - for (i, &elt) in enumerate(&insert) { + for (i, &elt) in insert.iter().enumerate() { assert_eq!(map.len(), i); map.insert(elt, elt); assert_eq!(map.len(), i + 1); @@ -1544,7 +1543,7 @@ mod tests { let present = vec![1, 6, 2]; let mut map = IndexMap::with_capacity(insert.len()); - for (i, &elt) in enumerate(&insert) { + for (i, &elt) in insert.iter().enumerate() { assert_eq!(map.len(), i); let (index, existing) = map.insert_full(elt, elt); assert_eq!(existing, None); @@ -1611,7 +1610,7 @@ mod tests { let not_present = [1, 3, 6, 9, 10]; let mut map = IndexMap::with_capacity(insert.len()); - for (i, &elt) in enumerate(&insert) { + for (i, &elt) in insert.iter().enumerate() { assert_eq!(map.len(), i); map.insert(elt, elt); assert_eq!(map.len(), i + 1); diff --git a/src/set.rs b/src/set.rs index cff168c8..387168d4 100644 --- a/src/set.rs +++ b/src/set.rs @@ -1366,7 +1366,6 @@ where #[cfg(test)] mod tests { use super::*; - use crate::util::enumerate; use std::string::String; #[test] @@ -1395,7 +1394,7 @@ mod tests { let not_present = [1, 3, 6, 9, 10]; let mut set = IndexSet::with_capacity(insert.len()); - for (i, &elt) in enumerate(&insert) { + for (i, &elt) in insert.iter().enumerate() { assert_eq!(set.len(), i); set.insert(elt); assert_eq!(set.len(), i + 1); @@ -1414,7 +1413,7 @@ mod tests { let present = vec![1, 6, 2]; let mut set = IndexSet::with_capacity(insert.len()); - for (i, &elt) in enumerate(&insert) { + for (i, &elt) in insert.iter().enumerate() { assert_eq!(set.len(), i); let (index, success) = set.insert_full(elt); assert!(success); @@ -1501,7 +1500,7 @@ mod tests { let not_present = [1, 3, 6, 9, 10]; let mut set = IndexSet::with_capacity(replace.len()); - for (i, &elt) in enumerate(&replace) { + for (i, &elt) in replace.iter().enumerate() { assert_eq!(set.len(), i); set.replace(elt); assert_eq!(set.len(), i + 1); @@ -1520,7 +1519,7 @@ mod tests { let present = vec![1, 6, 2]; let mut set = IndexSet::with_capacity(replace.len()); - for (i, &elt) in enumerate(&replace) { + for (i, &elt) in replace.iter().enumerate() { assert_eq!(set.len(), i); let (index, replaced) = set.replace_full(elt); assert!(replaced.is_none()); @@ -1607,7 +1606,7 @@ mod tests { let not_present = [1, 3, 6, 9, 10]; let mut set = IndexSet::with_capacity(insert.len()); - for (i, &elt) in enumerate(&insert) { + for (i, &elt) in insert.iter().enumerate() { assert_eq!(set.len(), i); set.insert(elt); assert_eq!(set.len(), i + 1); diff --git a/src/util.rs b/src/util.rs index 5388f470..a24dfafd 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,17 +1,9 @@ -use core::iter::Enumerate; use core::ops::{Bound, Range, RangeBounds}; pub(crate) fn third(t: (A, B, C)) -> C { t.2 } -pub(crate) fn enumerate(iterable: I) -> Enumerate -where - I: IntoIterator, -{ - iterable.into_iter().enumerate() -} - pub(crate) fn simplify_range(range: R, len: usize) -> Range where R: RangeBounds, From 931aaf580dd0dffb90e3e19fb77a8f3937f68f3b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 12:20:31 -0800 Subject: [PATCH 08/16] Make get_index_mut return &K, and add get_index_mut2 --- src/map.rs | 19 ++----------------- src/mutable_keys.rs | 24 ++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/map.rs b/src/map.rs index 932a3b2d..4c6a0229 100644 --- a/src/map.rs +++ b/src/map.rs @@ -479,21 +479,6 @@ where } } - pub(crate) fn get_full_mut2_impl( - &mut self, - key: &Q, - ) -> Option<(usize, &mut K, &mut V)> - where - Q: Hash + Equivalent, - { - if let Some(i) = self.get_index_of(key) { - let entry = &mut self.as_entries_mut()[i]; - Some((i, &mut entry.key, &mut entry.value)) - } else { - None - } - } - /// Remove the key-value pair equivalent to `key` and return /// its value. /// @@ -780,8 +765,8 @@ impl IndexMap { /// Valid indices are *0 <= index < self.len()* /// /// Computes in **O(1)** time. - pub fn get_index_mut(&mut self, index: usize) -> Option<(&mut K, &mut V)> { - self.as_entries_mut().get_mut(index).map(Bucket::muts) + pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { + self.as_entries_mut().get_mut(index).map(Bucket::ref_mut) } /// Get the first key-value pair diff --git a/src/mutable_keys.rs b/src/mutable_keys.rs index 35a90c47..fad7d60f 100644 --- a/src/mutable_keys.rs +++ b/src/mutable_keys.rs @@ -1,6 +1,6 @@ use core::hash::{BuildHasher, Hash}; -use super::{Equivalent, IndexMap}; +use super::{Bucket, Entries, Equivalent, IndexMap}; pub struct PrivateMarker {} @@ -21,6 +21,8 @@ pub trait MutableKeys { type Value; /// Return item index, mutable reference to key and value + /// + /// Computes in **O(1)** time (average). fn get_full_mut2( &mut self, key: &Q, @@ -28,6 +30,13 @@ pub trait MutableKeys { where Q: Hash + Equivalent; + /// Return mutable reference to key and value at an index. + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + fn get_index_mut2(&mut self, index: usize) -> Option<(&mut Self::Key, &mut Self::Value)>; + /// Scan through each key-value pair in the map and keep those where the /// closure `keep` returns `true`. /// @@ -39,6 +48,7 @@ pub trait MutableKeys { where F: FnMut(&mut Self::Key, &mut Self::Value) -> bool; + #[doc(hidden)] /// This method is not useful in itself – it is there to “seal” the trait /// for external implementation, so that we can add methods without /// causing breaking changes. @@ -55,11 +65,21 @@ where { type Key = K; type Value = V; + fn get_full_mut2(&mut self, key: &Q) -> Option<(usize, &mut K, &mut V)> where Q: Hash + Equivalent, { - self.get_full_mut2_impl(key) + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some((i, &mut entry.key, &mut entry.value)) + } else { + None + } + } + + fn get_index_mut2(&mut self, index: usize) -> Option<(&mut K, &mut V)> { + self.as_entries_mut().get_mut(index).map(Bucket::muts) } fn retain2(&mut self, keep: F) From bdba2a65005bc22d414720c19ab9999ddfec236e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 13:36:29 -0800 Subject: [PATCH 09/16] Convert the README to markdown --- README.md | 55 +++++++++++++++++++++++++++++++++++++++++++ README.rst | 69 ------------------------------------------------------ 2 files changed, 55 insertions(+), 69 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 00000000..a227e23d --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# indexmap + +[![build status](https://github.com/bluss/indexmap/workflows/Continuous%20integration/badge.svg?branch=master)](https://github.com/bluss/indexmap/actions) +[![crates.io](https://img.shields.io/crates/v/indexmap.svg)](https://crates.io/crates/indexmap) +[![docs](https://docs.rs/indexmap/badge.svg)](https://docs.rs/indexmap) +[![rustc](https://img.shields.io/badge/rust-1.56%2B-orange.svg)](https://img.shields.io/badge/rust-1.56%2B-orange.svg) + +A pure-Rust hash table which preserves (in a limited sense) insertion order. + +This crate implements compact map and set data-structures, +where the iteration order of the keys is independent from their hash or +value. It preserves insertion order (except after removals), and it +allows lookup of entries by either hash table key or numerical index. + +Note: this crate was originally released under the name `ordermap`, +but it was renamed to `indexmap` to better reflect its features. + +# Background + +This was inspired by Python 3.6's new dict implementation (which remembers +the insertion order and is fast to iterate, and is compact in memory). + +Some of those features were translated to Rust, and some were not. The result +was indexmap, a hash table that has following properties: + +- Order is **independent of hash function** and hash values of keys. +- Fast to iterate. +- Indexed in compact space. +- Preserves insertion order **as long** as you don't call `.remove()`. +- Uses hashbrown for the inner table, just like Rust's libstd `HashMap` does. + +## Performance + +`IndexMap` derives a couple of performance facts directly from how it is constructed, +which is roughly: + +> A raw hash table of key-value indices, and a vector of key-value pairs. + +- Iteration is very fast since it is on the dense key-values. +- Removal is fast since it moves memory areas only in the table, + and uses a single swap in the vector. +- Lookup is fast-ish because the initial 7-bit hash lookup uses SIMD, and indices are + densely stored. Lookup also is slow-ish since the actual key-value pairs are stored + separately. (Visible when cpu caches size is limiting.) + +- In practice, `IndexMap` has been tested out as the hashmap in rustc in [PR45282] and + the performance was roughly on par across the whole workload. +- If you want the properties of `IndexMap`, or its strongest performance points + fits your workload, it might be the best hash table implementation. + +[PR45282]: https://github.com/rust-lang/rust/pull/45282 + +# Recent Changes + +See [RELEASES.rst](https://github.com/bluss/indexmap/blob/master/README.rst). diff --git a/README.rst b/README.rst deleted file mode 100644 index 4dac24f4..00000000 --- a/README.rst +++ /dev/null @@ -1,69 +0,0 @@ -indexmap -======== - -|build_status|_ |crates|_ |docs|_ |rustc|_ - -.. |build_status| image:: https://github.com/bluss/indexmap/workflows/Continuous%20integration/badge.svg?branch=master -.. _build_status: https://github.com/bluss/indexmap/actions - -.. |crates| image:: https://img.shields.io/crates/v/indexmap.svg -.. _crates: https://crates.io/crates/indexmap - -.. |docs| image:: https://docs.rs/indexmap/badge.svg -.. _docs: https://docs.rs/indexmap - -.. |rustc| image:: https://img.shields.io/badge/rust-1.56%2B-orange.svg -.. _rustc: https://img.shields.io/badge/rust-1.56%2B-orange.svg - -A pure-Rust hash table which preserves (in a limited sense) insertion order. - -This crate implements compact map and set data-structures, -where the iteration order of the keys is independent from their hash or -value. It preserves insertion order (except after removals), and it -allows lookup of entries by either hash table key or numerical index. - -Note: this crate was originally released under the name ``ordermap``, -but it was renamed to ``indexmap`` to better reflect its features. - -Background -========== - -This was inspired by Python 3.6's new dict implementation (which remembers -the insertion order and is fast to iterate, and is compact in memory). - -Some of those features were translated to Rust, and some were not. The result -was indexmap, a hash table that has following properties: - -- Order is **independent of hash function** and hash values of keys. -- Fast to iterate. -- Indexed in compact space. -- Preserves insertion order **as long** as you don't call ``.remove()``. -- Uses hashbrown for the inner table, just like Rust's libstd ``HashMap`` does. - -Performance ------------ - -``IndexMap`` derives a couple of performance facts directly from how it is constructed, -which is roughly: - - A raw hash table of key-value indices, and a vector of key-value pairs. - -- Iteration is very fast since it is on the dense key-values. -- Removal is fast since it moves memory areas only in the table, - and uses a single swap in the vector. -- Lookup is fast-ish because the initial 7-bit hash lookup uses SIMD, and indices are - densely stored. Lookup also is slow-ish since the actual key-value pairs are stored - separately. (Visible when cpu caches size is limiting.) - -- In practice, ``IndexMap`` has been tested out as the hashmap in rustc in PR45282_ and - the performance was roughly on par across the whole workload. -- If you want the properties of ``IndexMap``, or its strongest performance points - fits your workload, it might be the best hash table implementation. - -.. _PR45282: https://github.com/rust-lang/rust/pull/45282 - - -Recent Changes -============== - -See `RELEASES.rst <./RELEASES.rst>`_. From dec33378bbf8490ca30eefd40dc255d12763479f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 15:54:37 -0800 Subject: [PATCH 10/16] Convert the RELEASES doc to markdown --- README.md | 2 +- RELEASES.md | 354 +++++++++++++++++++++++++++++++++++++++++++++++++++ RELEASES.rst | 354 --------------------------------------------------- 3 files changed, 355 insertions(+), 355 deletions(-) create mode 100644 RELEASES.md delete mode 100644 RELEASES.rst diff --git a/README.md b/README.md index a227e23d..5dc3f181 100644 --- a/README.md +++ b/README.md @@ -52,4 +52,4 @@ which is roughly: # Recent Changes -See [RELEASES.rst](https://github.com/bluss/indexmap/blob/master/README.rst). +See [RELEASES.md](https://github.com/bluss/indexmap/blob/master/README.md). diff --git a/RELEASES.md b/RELEASES.md new file mode 100644 index 00000000..e217c5a8 --- /dev/null +++ b/RELEASES.md @@ -0,0 +1,354 @@ +- 1.8.1 + + - The new `IndexSet::replace_full` will return the index of the item along + with the replaced value, if any, by @zakcutner in PR [222]. + +[222]: https://github.com/bluss/indexmap/pull/222 + +- 1.8.0 + + - The new `IndexMap::into_keys` and `IndexMap::into_values` will consume + the map into keys or values, respectively, matching Rust 1.54's `HashMap` + methods, by @taiki-e in PR [195]. + + - More of the iterator types implement `Debug`, `ExactSizeIterator`, and + `FusedIterator`, by @cuviper in PR [196]. + + - `IndexMap` and `IndexSet` now implement rayon's `ParallelDrainRange`, + by @cuviper in PR [197]. + + - `IndexMap::with_hasher` and `IndexSet::with_hasher` are now `const` + functions, allowing static maps and sets, by @mwillsey in PR [203]. + + - `IndexMap` and `IndexSet` now implement `From` for arrays, matching + Rust 1.56's implementation for `HashMap`, by @rouge8 in PR [205]. + + - `IndexMap` and `IndexSet` now have methods `sort_unstable_keys`, + `sort_unstable_by`, `sorted_unstable_by`, and `par_*` equivalents, + which sort in-place without preserving the order of equal items, by + @bhgomes in PR [211]. + +[195]: https://github.com/bluss/indexmap/pull/195 +[196]: https://github.com/bluss/indexmap/pull/196 +[197]: https://github.com/bluss/indexmap/pull/197 +[203]: https://github.com/bluss/indexmap/pull/203 +[205]: https://github.com/bluss/indexmap/pull/205 +[211]: https://github.com/bluss/indexmap/pull/211 + +- 1.7.0 + + - **MSRV**: Rust 1.49 or later is now required. + + - The `hashbrown` dependency has been updated to version 0.11. + +- 1.6.2 + + - Fixed to match `std` behavior, `OccupiedEntry::key` now references the + existing key in the map instead of the lookup key, by @cuviper in PR [170]. + + - The new `Entry::or_insert_with_key` matches Rust 1.50's `Entry` method, + passing `&K` to the callback to create a value, by @cuviper in PR [175]. + +[170]: https://github.com/bluss/indexmap/pull/170 +[175]: https://github.com/bluss/indexmap/pull/175 + +- 1.6.1 + + - The new `serde_seq` module implements `IndexMap` serialization as a + sequence to ensure order is preserved, by @cuviper in PR [158]. + + - New methods on maps and sets work like the `Vec`/slice methods by the same name: + `truncate`, `split_off`, `first`, `first_mut`, `last`, `last_mut`, and + `swap_indices`, by @cuviper in PR [160]. + +[158]: https://github.com/bluss/indexmap/pull/158 +[160]: https://github.com/bluss/indexmap/pull/160 + +- 1.6.0 + + - **MSRV**: Rust 1.36 or later is now required. + + - The `hashbrown` dependency has been updated to version 0.9. + +- 1.5.2 + + - The new "std" feature will force the use of `std` for users that explicitly + want the default `S = RandomState`, bypassing the autodetection added in 1.3.0, + by @cuviper in PR [145]. + +[145]: https://github.com/bluss/indexmap/pull/145 + +- 1.5.1 + + - Values can now be indexed by their `usize` position by @cuviper in PR [132]. + + - Some of the generic bounds have been relaxed to match `std` by @cuviper in PR [141]. + + - `drain` now accepts any `R: RangeBounds` by @cuviper in PR [142]. + +[132]: https://github.com/bluss/indexmap/pull/132 +[141]: https://github.com/bluss/indexmap/pull/141 +[142]: https://github.com/bluss/indexmap/pull/142 + +- 1.5.0 + + - **MSRV**: Rust 1.32 or later is now required. + + - The inner hash table is now based on `hashbrown` by @cuviper in PR [131]. + This also completes the method `reserve` and adds `shrink_to_fit`. + + - Add new methods `get_key_value`, `remove_entry`, `swap_remove_entry`, + and `shift_remove_entry`, by @cuviper in PR [136] + + - `Clone::clone_from` reuses allocations by @cuviper in PR [125] + + - Add new method `reverse` by @linclelinkpart5 in PR [128] + +[125]: https://github.com/bluss/indexmap/pull/125 +[128]: https://github.com/bluss/indexmap/pull/128 +[131]: https://github.com/bluss/indexmap/pull/131 +[136]: https://github.com/bluss/indexmap/pull/136 + +- 1.4.0 + + - Add new method `get_index_of` by @Thermatrix in PR [115] and [120] + + - Fix build script rebuild-if-changed configuration to use "build.rs"; + fixes issue [123]. Fix by @cuviper. + + - Dev-dependencies (rand and quickcheck) have been updated. The crate's tests + now run using Rust 1.32 or later (MSRV for building the crate has not changed). + by @kjeremy and @bluss + +[123]: https://github.com/bluss/indexmap/issues/123 +[115]: https://github.com/bluss/indexmap/pull/115 +[120]: https://github.com/bluss/indexmap/pull/120 + +- 1.3.2 + + - Maintenance update to regenerate the published `Cargo.toml`. + +- 1.3.1 + + - Maintenance update for formatting and `autocfg` 1.0. + +- 1.3.0 + + - The deprecation messages in the previous version have been removed. + (The methods have not otherwise changed.) Docs for removal methods have been + improved. + - From Rust 1.36, this crate supports being built **without std**, requiring + `alloc` instead. This is enabled automatically when it is detected that + `std` is not available. There is no crate feature to enable/disable to + trigger this. The new build-dep `autocfg` enables this. + +- 1.2.0 + + - Plain `.remove()` now has a deprecation message, it informs the user + about picking one of the removal functions `swap_remove` and `shift_remove` + which have different performance and order semantics. + Plain `.remove()` will not be removed, the warning message and method + will remain until further. + + - Add new method `shift_remove` for order preserving removal on the map, + and `shift_take` for the corresponding operation on the set. + + - Add methods `swap_remove`, `swap_remove_entry` to `Entry`. + + - Fix indexset/indexmap to support full paths, like `indexmap::indexmap!()` + + - Internal improvements: fix warnings, deprecations and style lints + +- 1.1.0 + + - Added optional feature `"rayon"` that adds parallel iterator support + to `IndexMap` and `IndexSet` using Rayon. This includes all the regular + iterators in parallel versions, and parallel sort. + + - Implemented `Clone` for `map::{Iter, Keys, Values}` and + `set::{Difference, Intersection, Iter, SymmetricDifference, Union}` + + - Implemented `Debug` for `map::{Entry, IntoIter, Iter, Keys, Values}` and + `set::{Difference, Intersection, IntoIter, Iter, SymmetricDifference, Union}` + + - Serde trait `IntoDeserializer` are implemented for `IndexMap` and `IndexSet`. + + - Minimum Rust version requirement increased to Rust 1.30 for development builds. + +- 1.0.2 + + - The new methods `IndexMap::insert_full` and `IndexSet::insert_full` are + both like `insert` with the index included in the return value. + + - The new method `Entry::and_modify` can be used to modify occupied + entries, matching the new methods of `std` maps in Rust 1.26. + + - The new method `Entry::or_default` inserts a default value in unoccupied + entries, matching the new methods of `std` maps in Rust 1.28. + +- 1.0.1 + + - Document Rust version policy for the crate (see rustdoc) + +- 1.0.0 + + - This is the 1.0 release for `indexmap`! (the crate and datastructure + formerly known as “ordermap”) + - `OccupiedEntry::insert` changed its signature, to use `&mut self` for + the method receiver, matching the equivalent method for a standard + `HashMap`. Thanks to @dtolnay for finding this bug. + - The deprecated old names from ordermap were removed: `OrderMap`, + `OrderSet`, `ordermap!{}`, `orderset!{}`. Use the new `IndexMap` + etc names instead. + +- 0.4.1 + + - Renamed crate to `indexmap`; the `ordermap` crate is now deprecated + and the types `OrderMap/Set` now have a deprecation notice. + +- 0.4.0 + + - This is the last release series for this `ordermap` under that name, + because the crate is **going to be renamed** to `indexmap` (with types + `IndexMap`, `IndexSet`) and no change in functionality! + - The map and its associated structs moved into the `map` submodule of the + crate, so that the map and set are symmetric + + + The iterators, `Entry` and other structs are now under `ordermap::map::` + + - Internally refactored `OrderMap` so that all the main algorithms + (insertion, lookup, removal etc) that don't use the `S` parameter (the + hasher) are compiled without depending on `S`, which reduces generics bloat. + + - `Entry` no longer has a type parameter `S`, which is just like + the standard `HashMap`'s entry. + + - Minimum Rust version requirement increased to Rust 1.18 + +- 0.3.5 + + - Documentation improvements + +- 0.3.4 + + - The `.retain()` methods for `OrderMap` and `OrderSet` now + traverse the elements in order, and the retained elements **keep their order** + - Added new methods `.sort_by()`, `.sort_keys()` to `OrderMap` and + `.sort_by()`, `.sort()` to `OrderSet`. These methods allow you to + sort the maps in place efficiently. + +- 0.3.3 + + - Document insertion behaviour better by @lucab + - Updated dependences (no feature changes) by @ignatenkobrain + +- 0.3.2 + + - Add `OrderSet` by @cuviper! + - `OrderMap::drain` is now (too) a double ended iterator. + +- 0.3.1 + + - In all ordermap iterators, forward the `collect` method to the underlying + iterator as well. + - Add crates.io categories. + +- 0.3.0 + + - The methods `get_pair`, `get_pair_index` were both replaced by + `get_full` (and the same for the mutable case). + - Method `swap_remove_pair` replaced by `swap_remove_full`. + - Add trait `MutableKeys` for opt-in mutable key access. Mutable key access + is only possible through the methods of this extension trait. + - Add new trait `Equivalent` for key equivalence. This extends the + `Borrow` trait mechanism for `OrderMap::get` in a backwards compatible + way, just some minor type inference related issues may become apparent. + See [#10] for more information. + - Implement `Extend<(&K, &V)>` by @xfix. + +[#10]: https://github.com/bluss/ordermap/pull/10 + +- 0.2.13 + + - Fix deserialization to support custom hashers by @Techcable. + - Add methods `.index()` on the entry types by @garro95. + +- 0.2.12 + + - Add methods `.with_hasher()`, `.hasher()`. + +- 0.2.11 + + - Support `ExactSizeIterator` for the iterators. By @Binero. + - Use `Box<[Pos]>` internally, saving a word in the `OrderMap` struct. + - Serde support, with crate feature `"serde-1"`. By @xfix. + +- 0.2.10 + + - Add iterator `.drain(..)` by @stevej. + +- 0.2.9 + + - Add method `.is_empty()` by @overvenus. + - Implement `PartialEq, Eq` by @overvenus. + - Add method `.sorted_by()`. + +- 0.2.8 + + - Add iterators `.values()` and `.values_mut()`. + - Fix compatibility with 32-bit platforms. + +- 0.2.7 + + - Add `.retain()`. + +- 0.2.6 + + - Add `OccupiedEntry::remove_entry` and other minor entry methods, + so that it now has all the features of `HashMap`'s entries. + +- 0.2.5 + + - Improved `.pop()` slightly. + +- 0.2.4 + + - Improved performance of `.insert()` ([#3]) by @pczarn. + +[#3]: https://github.com/bluss/ordermap/pull/3 + +- 0.2.3 + + - Generalize `Entry` for now, so that it works on hashmaps with non-default + hasher. However, there's a lingering compat issue since libstd `HashMap` + does not parameterize its entries by the hasher (`S` typarm). + - Special case some iterator methods like `.nth()`. + +- 0.2.2 + + - Disable the verbose `Debug` impl by default. + +- 0.2.1 + + - Fix doc links and clarify docs. + +- 0.2.0 + + - Add more `HashMap` methods & compat with its API. + - Experimental support for `.entry()` (the simplest parts of the API). + - Add `.reserve()` (placeholder impl). + - Add `.remove()` as synonym for `.swap_remove()`. + - Changed `.insert()` to swap value if the entry already exists, and + return `Option`. + - Experimental support as an *indexed* hash map! Added methods + `.get_index()`, `.get_index_mut()`, `.swap_remove_index()`, + `.get_pair_index()`, `.get_pair_index_mut()`. + +- 0.1.2 + + - Implement the 32/32 split idea for `Pos` which improves cache utilization + and lookup performance. + +- 0.1.1 + + - Initial release. diff --git a/RELEASES.rst b/RELEASES.rst deleted file mode 100644 index 402724a2..00000000 --- a/RELEASES.rst +++ /dev/null @@ -1,354 +0,0 @@ -- 1.8.1 - - - The new ``IndexSet::replace_full`` will return the index of the item along - with the replaced value, if any, by @zakcutner in PR 222_. - -.. _222: https://github.com/bluss/indexmap/pull/222 - -- 1.8.0 - - - The new ``IndexMap::into_keys`` and ``IndexMap::into_values`` will consume - the map into keys or values, respectively, matching Rust 1.54's ``HashMap`` - methods, by @taiki-e in PR 195_. - - - More of the iterator types implement ``Debug``, ``ExactSizeIterator``, and - ``FusedIterator``, by @cuviper in PR 196_. - - - ``IndexMap`` and ``IndexSet`` now implement rayon's ``ParallelDrainRange``, - by @cuviper in PR 197_. - - - ``IndexMap::with_hasher`` and ``IndexSet::with_hasher`` are now ``const`` - functions, allowing static maps and sets, by @mwillsey in PR 203_. - - - ``IndexMap`` and ``IndexSet`` now implement ``From`` for arrays, matching - Rust 1.56's implementation for ``HashMap``, by @rouge8 in PR 205_. - - - ``IndexMap`` and ``IndexSet`` now have methods ``sort_unstable_keys``, - ``sort_unstable_by``, ``sorted_unstable_by``, and ``par_*`` equivalents, - which sort in-place without preserving the order of equal items, by - @bhgomes in PR 211_. - -.. _195: https://github.com/bluss/indexmap/pull/195 -.. _196: https://github.com/bluss/indexmap/pull/196 -.. _197: https://github.com/bluss/indexmap/pull/197 -.. _203: https://github.com/bluss/indexmap/pull/203 -.. _205: https://github.com/bluss/indexmap/pull/205 -.. _211: https://github.com/bluss/indexmap/pull/211 - -- 1.7.0 - - - **MSRV**: Rust 1.49 or later is now required. - - - The ``hashbrown`` dependency has been updated to version 0.11. - -- 1.6.2 - - - Fixed to match ``std`` behavior, ``OccupiedEntry::key`` now references the - existing key in the map instead of the lookup key, by @cuviper in PR 170_. - - - The new ``Entry::or_insert_with_key`` matches Rust 1.50's ``Entry`` method, - passing ``&K`` to the callback to create a value, by @cuviper in PR 175_. - -.. _170: https://github.com/bluss/indexmap/pull/170 -.. _175: https://github.com/bluss/indexmap/pull/175 - -- 1.6.1 - - - The new ``serde_seq`` module implements ``IndexMap`` serialization as a - sequence to ensure order is preserved, by @cuviper in PR 158_. - - - New methods on maps and sets work like the ``Vec``/slice methods by the same name: - ``truncate``, ``split_off``, ``first``, ``first_mut``, ``last``, ``last_mut``, and - ``swap_indices``, by @cuviper in PR 160_. - -.. _158: https://github.com/bluss/indexmap/pull/158 -.. _160: https://github.com/bluss/indexmap/pull/160 - -- 1.6.0 - - - **MSRV**: Rust 1.36 or later is now required. - - - The ``hashbrown`` dependency has been updated to version 0.9. - -- 1.5.2 - - - The new "std" feature will force the use of ``std`` for users that explicitly - want the default ``S = RandomState``, bypassing the autodetection added in 1.3.0, - by @cuviper in PR 145_. - -.. _145: https://github.com/bluss/indexmap/pull/145 - -- 1.5.1 - - - Values can now be indexed by their ``usize`` position by @cuviper in PR 132_. - - - Some of the generic bounds have been relaxed to match ``std`` by @cuviper in PR 141_. - - - ``drain`` now accepts any ``R: RangeBounds`` by @cuviper in PR 142_. - -.. _132: https://github.com/bluss/indexmap/pull/132 -.. _141: https://github.com/bluss/indexmap/pull/141 -.. _142: https://github.com/bluss/indexmap/pull/142 - -- 1.5.0 - - - **MSRV**: Rust 1.32 or later is now required. - - - The inner hash table is now based on ``hashbrown`` by @cuviper in PR 131_. - This also completes the method ``reserve`` and adds ``shrink_to_fit``. - - - Add new methods ``get_key_value``, ``remove_entry``, ``swap_remove_entry``, - and ``shift_remove_entry``, by @cuviper in PR 136_ - - - ``Clone::clone_from`` reuses allocations by @cuviper in PR 125_ - - - Add new method ``reverse`` by @linclelinkpart5 in PR 128_ - -.. _125: https://github.com/bluss/indexmap/pull/125 -.. _128: https://github.com/bluss/indexmap/pull/128 -.. _131: https://github.com/bluss/indexmap/pull/131 -.. _136: https://github.com/bluss/indexmap/pull/136 - -- 1.4.0 - - - Add new method ``get_index_of`` by @Thermatrix in PR 115_ and 120_ - - - Fix build script rebuild-if-changed configuration to use "build.rs"; - fixes issue 123_. Fix by @cuviper. - - - Dev-dependencies (rand and quickcheck) have been updated. The crate's tests - now run using Rust 1.32 or later (MSRV for building the crate has not changed). - by @kjeremy and @bluss - -.. _123: https://github.com/bluss/indexmap/issues/123 -.. _115: https://github.com/bluss/indexmap/pull/115 -.. _120: https://github.com/bluss/indexmap/pull/120 - -- 1.3.2 - - - Maintenance update to regenerate the published `Cargo.toml`. - -- 1.3.1 - - - Maintenance update for formatting and ``autocfg`` 1.0. - -- 1.3.0 - - - The deprecation messages in the previous version have been removed. - (The methods have not otherwise changed.) Docs for removal methods have been - improved. - - From Rust 1.36, this crate supports being built **without std**, requiring - ``alloc`` instead. This is enabled automatically when it is detected that - ``std`` is not available. There is no crate feature to enable/disable to - trigger this. The new build-dep ``autocfg`` enables this. - -- 1.2.0 - - - Plain ``.remove()`` now has a deprecation message, it informs the user - about picking one of the removal functions ``swap_remove`` and ``shift_remove`` - which have different performance and order semantics. - Plain ``.remove()`` will not be removed, the warning message and method - will remain until further. - - - Add new method ``shift_remove`` for order preserving removal on the map, - and ``shift_take`` for the corresponding operation on the set. - - - Add methods ``swap_remove``, ``swap_remove_entry`` to ``Entry``. - - - Fix indexset/indexmap to support full paths, like ``indexmap::indexmap!()`` - - - Internal improvements: fix warnings, deprecations and style lints - -- 1.1.0 - - - Added optional feature `"rayon"` that adds parallel iterator support - to `IndexMap` and `IndexSet` using Rayon. This includes all the regular - iterators in parallel versions, and parallel sort. - - - Implemented ``Clone`` for ``map::{Iter, Keys, Values}`` and - ``set::{Difference, Intersection, Iter, SymmetricDifference, Union}`` - - - Implemented ``Debug`` for ``map::{Entry, IntoIter, Iter, Keys, Values}`` and - ``set::{Difference, Intersection, IntoIter, Iter, SymmetricDifference, Union}`` - - - Serde trait ``IntoDeserializer`` are implemented for ``IndexMap`` and ``IndexSet``. - - - Minimum Rust version requirement increased to Rust 1.30 for development builds. - -- 1.0.2 - - - The new methods ``IndexMap::insert_full`` and ``IndexSet::insert_full`` are - both like ``insert`` with the index included in the return value. - - - The new method ``Entry::and_modify`` can be used to modify occupied - entries, matching the new methods of ``std`` maps in Rust 1.26. - - - The new method ``Entry::or_default`` inserts a default value in unoccupied - entries, matching the new methods of ``std`` maps in Rust 1.28. - -- 1.0.1 - - - Document Rust version policy for the crate (see rustdoc) - -- 1.0.0 - - - This is the 1.0 release for ``indexmap``! (the crate and datastructure - formerly known as “ordermap”) - - ``OccupiedEntry::insert`` changed its signature, to use ``&mut self`` for - the method receiver, matching the equivalent method for a standard - ``HashMap``. Thanks to @dtolnay for finding this bug. - - The deprecated old names from ordermap were removed: ``OrderMap``, - ``OrderSet``, ``ordermap!{}``, ``orderset!{}``. Use the new ``IndexMap`` - etc names instead. - -- 0.4.1 - - - Renamed crate to ``indexmap``; the ``ordermap`` crate is now deprecated - and the types ``OrderMap/Set`` now have a deprecation notice. - -- 0.4.0 - - - This is the last release series for this ``ordermap`` under that name, - because the crate is **going to be renamed** to ``indexmap`` (with types - ``IndexMap``, ``IndexSet``) and no change in functionality! - - The map and its associated structs moved into the ``map`` submodule of the - crate, so that the map and set are symmetric - - + The iterators, ``Entry`` and other structs are now under ``ordermap::map::`` - - - Internally refactored ``OrderMap`` so that all the main algorithms - (insertion, lookup, removal etc) that don't use the ``S`` parameter (the - hasher) are compiled without depending on ``S``, which reduces generics bloat. - - - ``Entry`` no longer has a type parameter ``S``, which is just like - the standard ``HashMap``'s entry. - - - Minimum Rust version requirement increased to Rust 1.18 - -- 0.3.5 - - - Documentation improvements - -- 0.3.4 - - - The ``.retain()`` methods for ``OrderMap`` and ``OrderSet`` now - traverse the elements in order, and the retained elements **keep their order** - - Added new methods ``.sort_by()``, ``.sort_keys()`` to ``OrderMap`` and - ``.sort_by()``, ``.sort()`` to ``OrderSet``. These methods allow you to - sort the maps in place efficiently. - -- 0.3.3 - - - Document insertion behaviour better by @lucab - - Updated dependences (no feature changes) by @ignatenkobrain - -- 0.3.2 - - - Add ``OrderSet`` by @cuviper! - - ``OrderMap::drain`` is now (too) a double ended iterator. - -- 0.3.1 - - - In all ordermap iterators, forward the ``collect`` method to the underlying - iterator as well. - - Add crates.io categories. - -- 0.3.0 - - - The methods ``get_pair``, ``get_pair_index`` were both replaced by - ``get_full`` (and the same for the mutable case). - - Method ``swap_remove_pair`` replaced by ``swap_remove_full``. - - Add trait ``MutableKeys`` for opt-in mutable key access. Mutable key access - is only possible through the methods of this extension trait. - - Add new trait ``Equivalent`` for key equivalence. This extends the - ``Borrow`` trait mechanism for ``OrderMap::get`` in a backwards compatible - way, just some minor type inference related issues may become apparent. - See `#10`__ for more information. - - Implement ``Extend<(&K, &V)>`` by @xfix. - -__ https://github.com/bluss/ordermap/pull/10 - -- 0.2.13 - - - Fix deserialization to support custom hashers by @Techcable. - - Add methods ``.index()`` on the entry types by @garro95. - -- 0.2.12 - - - Add methods ``.with_hasher()``, ``.hasher()``. - -- 0.2.11 - - - Support ``ExactSizeIterator`` for the iterators. By @Binero. - - Use ``Box<[Pos]>`` internally, saving a word in the ``OrderMap`` struct. - - Serde support, with crate feature ``"serde-1"``. By @xfix. - -- 0.2.10 - - - Add iterator ``.drain(..)`` by @stevej. - -- 0.2.9 - - - Add method ``.is_empty()`` by @overvenus. - - Implement ``PartialEq, Eq`` by @overvenus. - - Add method ``.sorted_by()``. - -- 0.2.8 - - - Add iterators ``.values()`` and ``.values_mut()``. - - Fix compatibility with 32-bit platforms. - -- 0.2.7 - - - Add ``.retain()``. - -- 0.2.6 - - - Add ``OccupiedEntry::remove_entry`` and other minor entry methods, - so that it now has all the features of ``HashMap``'s entries. - -- 0.2.5 - - - Improved ``.pop()`` slightly. - -- 0.2.4 - - - Improved performance of ``.insert()`` (`#3`__) by @pczarn. - -__ https://github.com/bluss/ordermap/pull/3 - -- 0.2.3 - - - Generalize ``Entry`` for now, so that it works on hashmaps with non-default - hasher. However, there's a lingering compat issue since libstd ``HashMap`` - does not parameterize its entries by the hasher (``S`` typarm). - - Special case some iterator methods like ``.nth()``. - -- 0.2.2 - - - Disable the verbose ``Debug`` impl by default. - -- 0.2.1 - - - Fix doc links and clarify docs. - -- 0.2.0 - - - Add more ``HashMap`` methods & compat with its API. - - Experimental support for ``.entry()`` (the simplest parts of the API). - - Add ``.reserve()`` (placeholder impl). - - Add ``.remove()`` as synonym for ``.swap_remove()``. - - Changed ``.insert()`` to swap value if the entry already exists, and - return ``Option``. - - Experimental support as an *indexed* hash map! Added methods - ``.get_index()``, ``.get_index_mut()``, ``.swap_remove_index()``, - ``.get_pair_index()``, ``.get_pair_index_mut()``. - -- 0.1.2 - - - Implement the 32/32 split idea for ``Pos`` which improves cache utilization - and lookup performance. - -- 0.1.1 - - - Initial release. From b41fc6b5ddd3a265d5b3daac947209cbbc0d025b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 16:14:11 -0800 Subject: [PATCH 11/16] Add preliminary release notes for 2.0.0 --- RELEASES.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index e217c5a8..d1051fc9 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,20 @@ +- 2.0.0 (pending) + + - **MSRV**: Rust 1.56 or later is now required. + + - The `hashbrown` dependency has been updated to version 0.12. + + - The `"std"` feature is no longer auto-detected. It is included in the + default feature set, or else can be enabled like any other Cargo feature. + + - The `"serde-1"` feature has been removed, leaving just the optional + `"serde"` dependency to be enabled like a feature itself. + + - `IndexMap::get_index_mut` now returns `Option<(&K, &mut V)>`, changing + the key part from `&mut K` to `&K`. There is also a new alternative + `MutableKeys::get_index_mut2` to access the former behavior. + + - 1.8.1 - The new `IndexSet::replace_full` will return the index of the item along From 4ddce3a976c1bc88a6373391da542729c4bb1815 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 17:14:59 -0800 Subject: [PATCH 12/16] impl Debug for IterMut and ValuesMut --- RELEASES.md | 2 ++ src/map.rs | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index d1051fc9..3bef4859 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,6 +13,8 @@ - `IndexMap::get_index_mut` now returns `Option<(&K, &mut V)>`, changing the key part from `&mut K` to `&K`. There is also a new alternative `MutableKeys::get_index_mut2` to access the former behavior. + + - `IterMut` and `ValuesMut` now implement `Debug`. - 1.8.1 diff --git a/src/map.rs b/src/map.rs index 4c6a0229..36291658 100644 --- a/src/map.rs +++ b/src/map.rs @@ -984,7 +984,12 @@ impl ExactSizeIterator for ValuesMut<'_, K, V> { impl FusedIterator for ValuesMut<'_, K, V> {} -// TODO: `impl Debug for ValuesMut` once we have MSRV 1.53 for `slice::IterMut::as_slice` +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} /// An owning iterator over the values of a `IndexMap`. /// @@ -1095,7 +1100,12 @@ impl ExactSizeIterator for IterMut<'_, K, V> { impl FusedIterator for IterMut<'_, K, V> {} -// TODO: `impl Debug for IterMut` once we have MSRV 1.53 for `slice::IterMut::as_slice` +impl fmt::Debug for IterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} /// An owning iterator over the entries of a `IndexMap`. /// From 42fab9923135e333fd91ca7f0678dc30be1f705f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 17:27:41 -0800 Subject: [PATCH 13/16] Use a more standard way to seal MutableKeys Ref: https://rust-lang.github.io/api-guidelines/future-proofing.html --- src/mutable_keys.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/mutable_keys.rs b/src/mutable_keys.rs index fad7d60f..7efc779b 100644 --- a/src/mutable_keys.rs +++ b/src/mutable_keys.rs @@ -2,8 +2,6 @@ use core::hash::{BuildHasher, Hash}; use super::{Bucket, Entries, Equivalent, IndexMap}; -pub struct PrivateMarker {} - /// Opt-in mutable access to keys. /// /// These methods expose `&mut K`, mutable references to the key as it is stored @@ -16,7 +14,9 @@ pub struct PrivateMarker {} /// implementing PartialEq, Eq, or Hash incorrectly would be). /// /// `use` this trait to enable its methods for `IndexMap`. -pub trait MutableKeys { +/// +/// This trait is sealed and cannot be implemented for types outside this crate. +pub trait MutableKeys: private::Sealed { type Key; type Value; @@ -47,12 +47,6 @@ pub trait MutableKeys { fn retain2(&mut self, keep: F) where F: FnMut(&mut Self::Key, &mut Self::Value) -> bool; - - #[doc(hidden)] - /// This method is not useful in itself – it is there to “seal” the trait - /// for external implementation, so that we can add methods without - /// causing breaking changes. - fn __private_marker(&self) -> PrivateMarker; } /// Opt-in mutable access to keys. @@ -88,8 +82,10 @@ where { self.retain_mut(keep) } +} - fn __private_marker(&self) -> PrivateMarker { - PrivateMarker {} - } +mod private { + pub trait Sealed {} + + impl Sealed for super::IndexMap {} } From 94d11970208e8937e9bd9187b4863706a81e19df Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Feb 2022 17:42:03 -0800 Subject: [PATCH 14/16] Add shrink_to --- RELEASES.md | 4 +++- src/map.rs | 9 ++++++++- src/map/core.rs | 8 ++++---- src/set.rs | 7 +++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 3bef4859..f27a0bc8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -15,7 +15,9 @@ `MutableKeys::get_index_mut2` to access the former behavior. - `IterMut` and `ValuesMut` now implement `Debug`. - + + - The new `IndexMap::shrink_to` and `IndexSet::shrink_to` methods shrink + the capacity with a lower bound. - 1.8.1 diff --git a/src/map.rs b/src/map.rs index 36291658..604538df 100644 --- a/src/map.rs +++ b/src/map.rs @@ -332,7 +332,14 @@ where /// /// Computes in **O(n)** time. pub fn shrink_to_fit(&mut self) { - self.core.shrink_to_fit(); + self.core.shrink_to(0); + } + + /// Shrink the capacity of the map with a lower limit. + /// + /// Computes in **O(n)** time. + pub fn shrink_to(&mut self, min_capacity: usize) { + self.core.shrink_to(min_capacity); } fn hash(&self, key: &Q) -> HashValue { diff --git a/src/map/core.rs b/src/map/core.rs index 0ed9b1ff..6479135d 100644 --- a/src/map/core.rs +++ b/src/map/core.rs @@ -201,10 +201,10 @@ impl IndexMapCore { self.entries.reserve_exact(additional); } - /// Shrink the capacity of the map as much as possible. - pub(crate) fn shrink_to_fit(&mut self) { - self.indices.shrink_to(0, get_hash(&self.entries)); - self.entries.shrink_to_fit(); + /// Shrink the capacity of the map with a lower bound + pub(crate) fn shrink_to(&mut self, min_capacity: usize) { + self.indices.shrink_to(min_capacity, get_hash(&self.entries)); + self.entries.shrink_to(min_capacity); } /// Remove the last key-value pair diff --git a/src/set.rs b/src/set.rs index 387168d4..fa157b0f 100644 --- a/src/set.rs +++ b/src/set.rs @@ -268,6 +268,13 @@ where self.map.shrink_to_fit(); } + /// Shrink the capacity of the set with a lower limit. + /// + /// Computes in **O(n)** time. + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity); + } + /// Insert the value into the set. /// /// If an equivalent item already exists in the set, it returns From 18b8a6f1495cc075662eb36595ad46d5ba5d896a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 9 Feb 2022 10:39:52 -0800 Subject: [PATCH 15/16] no_std has to opt-out of default features --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f04cce5a..fddcca0a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,7 +72,7 @@ jobs: target: ${{ matrix.target }} - name: Tests run: | - cargo build -vv --target=${{ matrix.target }} + cargo build -vv --target=${{ matrix.target }} --no-default-features cargo build -v -p test-nostd --target=${{ matrix.target }} clippy: From c71567597858e1b186479ad67247fe2d810eaabe Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 29 Mar 2022 16:16:29 -0700 Subject: [PATCH 16/16] Fix clippy::needless_borrow --- src/rayon/set.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rayon/set.rs b/src/rayon/set.rs index 5a4ac97d..6749dc0d 100644 --- a/src/rayon/set.rs +++ b/src/rayon/set.rs @@ -295,7 +295,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() - .entries(self.set1.difference(&self.set2)) + .entries(self.set1.difference(self.set2)) .finish() } } @@ -346,7 +346,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() - .entries(self.set1.intersection(&self.set2)) + .entries(self.set1.intersection(self.set2)) .finish() } } @@ -397,7 +397,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() - .entries(self.set1.symmetric_difference(&self.set2)) + .entries(self.set1.symmetric_difference(self.set2)) .finish() } } @@ -447,7 +447,7 @@ where S2: BuildHasher, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.set1.union(&self.set2)).finish() + f.debug_list().entries(self.set1.union(self.set2)).finish() } }