From 059f4affcc848c78edaeb063afef2ba622469591 Mon Sep 17 00:00:00 2001 From: Ian Joiner <14581281+iajoiner@users.noreply.github.com> Date: Thu, 3 Apr 2025 01:22:12 -0400 Subject: [PATCH 1/7] docs: provide link to `core::hash::BuildHasherDefault` in macro.rs docs (cherry picked from commit e2e97c1a1c1da9f227b0e6a9267350e94653c8c0) --- src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index bfe43fd..9cc57fc 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,5 +1,5 @@ /// Create an [`OrderMap`][crate::OrderMap] from a list of key-value pairs -/// and a `BuildHasherDefault`-wrapped custom hasher. +/// and a [`BuildHasherDefault`][core::hash::BuildHasherDefault]-wrapped custom hasher. /// /// ## Example /// @@ -73,7 +73,7 @@ macro_rules! ordermap { } /// Create an [`OrderSet`][crate::OrderSet] from a list of values -/// and a `BuildHasherDefault`-wrapped custom hasher. +/// and a [`BuildHasherDefault`][core::hash::BuildHasherDefault]-wrapped custom hasher. /// /// ## Example /// From b261aeb3a44991a0a7a541729b52b07ae82dcb1d Mon Sep 17 00:00:00 2001 From: Niklas Jonsson Date: Thu, 14 Jul 2022 19:52:18 +0200 Subject: [PATCH 2/7] Implement get_disjoint_mut for arrays of keys (cherry picked from commit 5aec9ec674d40f2c2da74ef6a335353cc41092dc) --- Cargo.toml | 2 +- src/map.rs | 35 +++++++++++++++++++ src/map/tests.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index eaef973..a255283 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.63" bench = false [dependencies] -indexmap = { version = "2.8.0", default-features = false } +indexmap = { version = "2.9.0", default-features = false } arbitrary = { version = "1.0", optional = true, default-features = false } quickcheck = { version = "1.0", optional = true, default-features = false } diff --git a/src/map.rs b/src/map.rs index afa5cac..9ba9801 100644 --- a/src/map.rs +++ b/src/map.rs @@ -677,6 +677,22 @@ where self.inner.get_full_mut(key) } + /// Return the values for `N` keys. If any key is missing a value, or there + /// are duplicate keys, `None` is returned. + /// + /// # Examples + /// + /// ``` + /// let mut map = ordermap::OrderMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); + /// assert_eq!(map.get_disjoint_mut([&2, &1]), Some([&mut 'c', &mut 'a'])); + /// ``` + pub fn get_disjoint_mut(&mut self, keys: [&Q; N]) -> Option<[&mut V; N]> + where + Q: Hash + Equivalent + ?Sized, + { + self.inner.get_disjoint_mut(keys) + } + /// Remove the key-value pair equivalent to `key` and return its value. /// /// **NOTE:** This is equivalent to [`IndexMap::shift_remove`], and @@ -1011,6 +1027,25 @@ impl OrderMap { self.inner.get_index_entry(index).map(IndexedEntry::new) } + /// Get an array of `N` key-value pairs by `N` indices + /// + /// Valid indices are *0 <= index < self.len()* and each index needs to be unique. + /// + /// Computes in **O(1)** time. + /// + /// # Examples + /// + /// ``` + /// let mut map = ordermap::OrderMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); + /// assert_eq!(map.get_disjoint_indices_mut([2, 0]), Some([(&2, &mut 'c'), (&1, &mut 'a')])); + /// ``` + pub fn get_disjoint_indices_mut( + &mut self, + indices: [usize; N], + ) -> Option<[(&K, &mut V); N]> { + self.inner.get_disjoint_indices_mut(indices) + } + /// Returns a slice of key-value pairs in the given range of indices. /// /// Valid indices are `0 <= index < self.len()`. diff --git a/src/map/tests.rs b/src/map/tests.rs index 5578130..4934c15 100644 --- a/src/map/tests.rs +++ b/src/map/tests.rs @@ -810,3 +810,94 @@ fn test_partition_point() { assert_eq!(b.partition_point(|_, &x| x < 7), 4); assert_eq!(b.partition_point(|_, &x| x < 8), 5); } + +#[test] +fn disjoint_mut_empty_map() { + let mut map: OrderMap = OrderMap::default(); + assert!(map.get_disjoint_mut([&0, &1, &2, &3]).is_none()); +} + +#[test] +fn disjoint_mut_empty_param() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + assert!(map.get_disjoint_mut([] as [&u32; 0]).is_some()); +} + +#[test] +fn disjoint_mut_single_fail() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + assert!(map.get_disjoint_mut([&0]).is_none()); +} + +#[test] +fn disjoint_mut_single_success() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + assert_eq!(map.get_disjoint_mut([&1]), Some([&mut 10])); +} + +#[test] +fn disjoint_mut_multi_success() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 100); + map.insert(2, 200); + map.insert(3, 300); + map.insert(4, 400); + assert_eq!(map.get_disjoint_mut([&1, &2]), Some([&mut 100, &mut 200])); + assert_eq!(map.get_disjoint_mut([&1, &3]), Some([&mut 100, &mut 300])); + assert_eq!( + map.get_disjoint_mut([&3, &1, &4, &2]), + Some([&mut 300, &mut 100, &mut 400, &mut 200]) + ); +} + +#[test] +fn disjoint_mut_multi_success_unsized_key() { + let mut map: OrderMap<&'static str, u32> = OrderMap::default(); + map.insert("1", 100); + map.insert("2", 200); + map.insert("3", 300); + map.insert("4", 400); + assert_eq!(map.get_disjoint_mut(["1", "2"]), Some([&mut 100, &mut 200])); + assert_eq!(map.get_disjoint_mut(["1", "3"]), Some([&mut 100, &mut 300])); + assert_eq!( + map.get_disjoint_mut(["3", "1", "4", "2"]), + Some([&mut 300, &mut 100, &mut 400, &mut 200]) + ); +} + +#[test] +fn disjoint_mut_multi_fail_missing() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + map.insert(1123, 100); + map.insert(321, 20); + map.insert(1337, 30); + assert_eq!(map.get_disjoint_mut([&121, &1123]), None); + assert_eq!(map.get_disjoint_mut([&1, &1337, &56]), None); + assert_eq!(map.get_disjoint_mut([&1337, &123, &321, &1, &1123]), None); +} + +#[test] +fn disjoint_mut_multi_fail_duplicate() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + map.insert(1123, 100); + map.insert(321, 20); + map.insert(1337, 30); + assert_eq!(map.get_disjoint_mut([&1, &1]), None); + assert_eq!( + map.get_disjoint_mut([&1337, &123, &321, &1337, &1, &1123]), + None + ); +} + +#[test] +fn many_index_mut_fail_oob() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!(map.get_disjoint_indices_mut([1, 3]), None); +} From c198a4db20bbcd2ccdbc35f70878fcc90dba4eee Mon Sep 17 00:00:00 2001 From: Niklas Jonsson Date: Sat, 1 Mar 2025 21:39:06 +0100 Subject: [PATCH 3/7] Address review feedback (cherry picked from commit 4e1d8cef470b4d96380ebbb8bae8994db1d79f51) --- src/lib.rs | 2 +- src/map.rs | 18 +++---- src/map/tests.rs | 133 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 119 insertions(+), 34 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f9bdcbf..e50038c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,4 +116,4 @@ pub mod set; pub use crate::map::OrderMap; pub use crate::set::OrderSet; -pub use indexmap::{Equivalent, TryReserveError}; +pub use indexmap::{Equivalent, GetDisjointMutError, TryReserveError}; diff --git a/src/map.rs b/src/map.rs index 9ba9801..4774f06 100644 --- a/src/map.rs +++ b/src/map.rs @@ -49,7 +49,7 @@ use alloc::vec::Vec; #[cfg(feature = "std")] use std::collections::hash_map::RandomState; -use crate::{Equivalent, TryReserveError}; +use crate::{Equivalent, GetDisjointMutError, TryReserveError}; /// A hash table where the iteration order of the key-value pairs is independent /// of the hash values of the keys. @@ -677,16 +677,16 @@ where self.inner.get_full_mut(key) } - /// Return the values for `N` keys. If any key is missing a value, or there - /// are duplicate keys, `None` is returned. + /// Return the values for `N` keys. If any key is duplicated, this function will panic. /// /// # Examples /// /// ``` /// let mut map = ordermap::OrderMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); - /// assert_eq!(map.get_disjoint_mut([&2, &1]), Some([&mut 'c', &mut 'a'])); + /// assert_eq!(map.get_disjoint_mut([&2, &1]), [Some(&mut 'c'), Some(&mut 'a')]); /// ``` - pub fn get_disjoint_mut(&mut self, keys: [&Q; N]) -> Option<[&mut V; N]> + #[allow(unsafe_code)] + pub fn get_disjoint_mut(&mut self, keys: [&Q; N]) -> [Option<&mut V>; N] where Q: Hash + Equivalent + ?Sized, { @@ -1031,19 +1031,17 @@ impl OrderMap { /// /// Valid indices are *0 <= index < self.len()* and each index needs to be unique. /// - /// Computes in **O(1)** time. - /// /// # Examples /// /// ``` /// let mut map = ordermap::OrderMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); - /// assert_eq!(map.get_disjoint_indices_mut([2, 0]), Some([(&2, &mut 'c'), (&1, &mut 'a')])); + /// assert_eq!(map.get_disjoint_indices_mut([2, 0]), Ok([(&2, &mut 'c'), (&1, &mut 'a')])); /// ``` pub fn get_disjoint_indices_mut( &mut self, indices: [usize; N], - ) -> Option<[(&K, &mut V); N]> { - self.inner.get_disjoint_indices_mut(indices) + ) -> Result<[(&K, &mut V); N], GetDisjointMutError> { + self.as_mut_slice().get_disjoint_mut(indices) } /// Returns a slice of key-value pairs in the given range of indices. diff --git a/src/map/tests.rs b/src/map/tests.rs index 4934c15..f590efc 100644 --- a/src/map/tests.rs +++ b/src/map/tests.rs @@ -814,28 +814,31 @@ fn test_partition_point() { #[test] fn disjoint_mut_empty_map() { let mut map: OrderMap = OrderMap::default(); - assert!(map.get_disjoint_mut([&0, &1, &2, &3]).is_none()); + assert_eq!( + map.get_disjoint_mut([&0, &1, &2, &3]), + [None, None, None, None] + ); } #[test] fn disjoint_mut_empty_param() { let mut map: OrderMap = OrderMap::default(); map.insert(1, 10); - assert!(map.get_disjoint_mut([] as [&u32; 0]).is_some()); + assert_eq!(map.get_disjoint_mut([] as [&u32; 0]), []); } #[test] fn disjoint_mut_single_fail() { let mut map: OrderMap = OrderMap::default(); map.insert(1, 10); - assert!(map.get_disjoint_mut([&0]).is_none()); + assert_eq!(map.get_disjoint_mut([&0]), [None]); } #[test] fn disjoint_mut_single_success() { let mut map: OrderMap = OrderMap::default(); map.insert(1, 10); - assert_eq!(map.get_disjoint_mut([&1]), Some([&mut 10])); + assert_eq!(map.get_disjoint_mut([&1]), [Some(&mut 10)]); } #[test] @@ -845,11 +848,22 @@ fn disjoint_mut_multi_success() { map.insert(2, 200); map.insert(3, 300); map.insert(4, 400); - assert_eq!(map.get_disjoint_mut([&1, &2]), Some([&mut 100, &mut 200])); - assert_eq!(map.get_disjoint_mut([&1, &3]), Some([&mut 100, &mut 300])); + assert_eq!( + map.get_disjoint_mut([&1, &2]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut([&1, &3]), + [Some(&mut 100), Some(&mut 300)] + ); assert_eq!( map.get_disjoint_mut([&3, &1, &4, &2]), - Some([&mut 300, &mut 100, &mut 400, &mut 200]) + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] ); } @@ -860,44 +874,117 @@ fn disjoint_mut_multi_success_unsized_key() { map.insert("2", 200); map.insert("3", 300); map.insert("4", 400); - assert_eq!(map.get_disjoint_mut(["1", "2"]), Some([&mut 100, &mut 200])); - assert_eq!(map.get_disjoint_mut(["1", "3"]), Some([&mut 100, &mut 300])); + + assert_eq!( + map.get_disjoint_mut(["1", "2"]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut(["1", "3"]), + [Some(&mut 100), Some(&mut 300)] + ); assert_eq!( map.get_disjoint_mut(["3", "1", "4", "2"]), - Some([&mut 300, &mut 100, &mut 400, &mut 200]) + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] + ); +} + +#[test] +fn disjoint_mut_multi_success_borrow_key() { + let mut map: OrderMap = OrderMap::default(); + map.insert("1".into(), 100); + map.insert("2".into(), 200); + map.insert("3".into(), 300); + map.insert("4".into(), 400); + + assert_eq!( + map.get_disjoint_mut(["1", "2"]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut(["1", "3"]), + [Some(&mut 100), Some(&mut 300)] + ); + assert_eq!( + map.get_disjoint_mut(["3", "1", "4", "2"]), + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] ); } #[test] fn disjoint_mut_multi_fail_missing() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 100); + map.insert(2, 200); + map.insert(3, 300); + map.insert(4, 400); + + assert_eq!(map.get_disjoint_mut([&1, &5]), [Some(&mut 100), None]); + assert_eq!(map.get_disjoint_mut([&5, &6]), [None, None]); + assert_eq!( + map.get_disjoint_mut([&1, &5, &4]), + [Some(&mut 100), None, Some(&mut 400)] + ); +} + +#[test] +#[should_panic] +fn disjoint_mut_multi_fail_duplicate_panic() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 100); + map.get_disjoint_mut([&1, &2, &1]); +} + +#[test] +fn disjoint_indices_mut_fail_oob() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!( + map.get_disjoint_indices_mut([1, 3]), + Err(crate::GetDisjointMutError::IndexOutOfBounds) + ); +} + +#[test] +fn disjoint_indices_mut_empty() { let mut map: OrderMap = OrderMap::default(); map.insert(1, 10); - map.insert(1123, 100); map.insert(321, 20); - map.insert(1337, 30); - assert_eq!(map.get_disjoint_mut([&121, &1123]), None); - assert_eq!(map.get_disjoint_mut([&1, &1337, &56]), None); - assert_eq!(map.get_disjoint_mut([&1337, &123, &321, &1, &1123]), None); + assert_eq!(map.get_disjoint_indices_mut([]), Ok([])); } #[test] -fn disjoint_mut_multi_fail_duplicate() { +fn disjoint_indices_mut_success() { let mut map: OrderMap = OrderMap::default(); map.insert(1, 10); - map.insert(1123, 100); map.insert(321, 20); - map.insert(1337, 30); - assert_eq!(map.get_disjoint_mut([&1, &1]), None); + assert_eq!(map.get_disjoint_indices_mut([0]), Ok([(&1, &mut 10)])); + + assert_eq!(map.get_disjoint_indices_mut([1]), Ok([(&321, &mut 20)])); assert_eq!( - map.get_disjoint_mut([&1337, &123, &321, &1337, &1, &1123]), - None + map.get_disjoint_indices_mut([0, 1]), + Ok([(&1, &mut 10), (&321, &mut 20)]) ); } #[test] -fn many_index_mut_fail_oob() { +fn disjoint_indices_mut_fail_duplicate() { let mut map: OrderMap = OrderMap::default(); map.insert(1, 10); map.insert(321, 20); - assert_eq!(map.get_disjoint_indices_mut([1, 3]), None); + assert_eq!( + map.get_disjoint_indices_mut([1, 2, 1]), + Err(crate::GetDisjointMutError::OverlappingIndices) + ); } From 53875750550e023da5cc263cf0d4f479ffa4f906 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 Apr 2025 14:42:19 -0700 Subject: [PATCH 4/7] Implement additional suggestions from review (cherry picked from commit 5be552d557765a8ccc919185838067b3c77eab95) --- src/map.rs | 3 +-- src/map/tests.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/map.rs b/src/map.rs index 4774f06..21c61d2 100644 --- a/src/map.rs +++ b/src/map.rs @@ -685,10 +685,9 @@ where /// let mut map = ordermap::OrderMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); /// assert_eq!(map.get_disjoint_mut([&2, &1]), [Some(&mut 'c'), Some(&mut 'a')]); /// ``` - #[allow(unsafe_code)] pub fn get_disjoint_mut(&mut self, keys: [&Q; N]) -> [Option<&mut V>; N] where - Q: Hash + Equivalent + ?Sized, + Q: ?Sized + Hash + Equivalent, { self.inner.get_disjoint_mut(keys) } diff --git a/src/map/tests.rs b/src/map/tests.rs index f590efc..5d6febd 100644 --- a/src/map/tests.rs +++ b/src/map/tests.rs @@ -984,7 +984,7 @@ fn disjoint_indices_mut_fail_duplicate() { map.insert(1, 10); map.insert(321, 20); assert_eq!( - map.get_disjoint_indices_mut([1, 2, 1]), + map.get_disjoint_indices_mut([1, 0, 1]), Err(crate::GetDisjointMutError::OverlappingIndices) ); } From 9e5f1ecb671dc485713a0c5af4d361aa7460b690 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 Apr 2025 16:42:55 -0700 Subject: [PATCH 5/7] Use `borsh/indexmap` instead of deprecated `indexmap/borsh` --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a255283..42b8870 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ indexmap = { version = "2.9.0", default-features = false } arbitrary = { version = "1.0", optional = true, default-features = false } quickcheck = { version = "1.0", optional = true, default-features = false } serde = { version = "1.0", optional = true, default-features = false } -borsh = { version = "1.2", optional = true, default-features = false } +borsh = { version = "1.5.6", optional = true, default-features = false } rayon = { version = "1.9", optional = true } [dev-dependencies] @@ -38,7 +38,7 @@ arbitrary = ["dep:arbitrary", "indexmap/arbitrary"] quickcheck = ["dep:quickcheck", "indexmap/quickcheck"] rayon = ["dep:rayon", "indexmap/rayon"] serde = ["dep:serde", "indexmap/serde"] -borsh = ["dep:borsh", "indexmap/borsh"] +borsh = ["dep:borsh", "borsh/indexmap"] [profile.bench] debug = true From a21398779591e74676f03fa411f1eb16ba026aaa Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 Apr 2025 16:44:50 -0700 Subject: [PATCH 6/7] Fix `map::tests::drain_range` to test `OrderMap` --- src/map/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/tests.rs b/src/map/tests.rs index 5d6febd..08c1c89 100644 --- a/src/map/tests.rs +++ b/src/map/tests.rs @@ -548,7 +548,7 @@ fn drain_range() { 20..30, // sweep everything ] { let mut vec = Vec::from_iter(0..100); - let mut map: IndexMap = (0..100).map(|i| (i, ())).collect(); + let mut map: OrderMap = (0..100).map(|i| (i, ())).collect(); drop(vec.drain(range.clone())); drop(map.drain(range)); assert!(vec.iter().eq(map.keys())); From 290871b1e503c48967c580473d2f1dfb51a1efb5 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 Apr 2025 16:48:52 -0700 Subject: [PATCH 7/7] Release 0.5.7 --- Cargo.toml | 2 +- RELEASES.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 42b8870..97e5c89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ordermap" edition = "2021" -version = "0.5.6" +version = "0.5.7" documentation = "https://docs.rs/ordermap/" repository = "https://github.com/indexmap-rs/ordermap" license = "Apache-2.0 OR MIT" diff --git a/RELEASES.md b/RELEASES.md index 7738f26..54454ae 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,13 @@ # Releases +## 0.5.7 (2025-04-04) + +- Added a `get_disjoint_mut` method to `OrderMap`, matching Rust 1.86's + `HashMap` method. +- Added a `get_disjoint_indices_mut` method to `OrderMap`, matching Rust 1.86's + `get_disjoint_mut` method on slices. +- Updated the `indexmap` dependency to version 2.9.0. + ## 0.5.6 (2025-03-10) - Added `ordermap_with_default!` and `orderset_with_default!` to be used with