Skip to content

Commit c9fd0af

Browse files
NiklasJonssoncuviper
authored andcommitted
Implement get_disjoint_mut for arrays of keys
(cherry picked from commit 5aec9ec674d40f2c2da74ef6a335353cc41092dc)
1 parent 4aac93f commit c9fd0af

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

src/map.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,37 @@ where
825825
}
826826
}
827827

828+
/// Return the values for `N` keys. If any key is missing a value, or there
829+
/// are duplicate keys, `None` is returned.
830+
///
831+
/// # Examples
832+
///
833+
/// ```
834+
/// let mut map = ringmap::RingMap::from([(1, 'a'), (3, 'b'), (2, 'c')]);
835+
/// assert_eq!(map.get_disjoint_mut([&2, &1]), Some([&mut 'c', &mut 'a']));
836+
/// ```
837+
pub fn get_disjoint_mut<Q, const N: usize>(&mut self, keys: [&Q; N]) -> Option<[&mut V; N]>
838+
where
839+
Q: Hash + Equivalent<K> + ?Sized,
840+
{
841+
let len = self.len();
842+
let indices = keys.map(|key| self.get_index_of(key));
843+
844+
// Handle out-of-bounds indices with panic as this is an internal error in get_index_of.
845+
for idx in indices {
846+
let idx = idx?;
847+
debug_assert!(
848+
idx < len,
849+
"Index is out of range! Got '{}' but length is '{}'",
850+
idx,
851+
len
852+
);
853+
}
854+
let indices = indices.map(Option::unwrap);
855+
let entries = self.get_disjoint_indices_mut(indices)?;
856+
Some(entries.map(|(_key, value)| value))
857+
}
858+
828859
/// Remove the key-value pair equivalent to `key` and return its value.
829860
///
830861
/// Like [`VecDeque::remove`], the pair is removed by shifting all of the
@@ -1286,6 +1317,44 @@ impl<K, V, S> RingMap<K, V, S> {
12861317
Some(IndexedEntry::new(&mut self.core, index))
12871318
}
12881319

1320+
/// Get an array of `N` key-value pairs by `N` indices
1321+
///
1322+
/// Valid indices are *0 <= index < self.len()* and each index needs to be unique.
1323+
///
1324+
/// Computes in **O(1)** time.
1325+
///
1326+
/// # Examples
1327+
///
1328+
/// ```
1329+
/// let mut map = ringmap::RingMap::from([(1, 'a'), (3, 'b'), (2, 'c')]);
1330+
/// assert_eq!(map.get_disjoint_indices_mut([2, 0]), Some([(&2, &mut 'c'), (&1, &mut 'a')]));
1331+
/// ```
1332+
pub fn get_disjoint_indices_mut<const N: usize>(
1333+
&mut self,
1334+
indices: [usize; N],
1335+
) -> Option<[(&K, &mut V); N]> {
1336+
// SAFETY: Can't allow duplicate indices as we would return several mutable refs to the same data.
1337+
let len = self.len();
1338+
for i in 0..N {
1339+
let idx = indices[i];
1340+
if idx >= len || indices[i + 1..N].contains(&idx) {
1341+
return None;
1342+
}
1343+
}
1344+
1345+
let entries_ptr = self.as_entries_mut().as_mut_ptr();
1346+
let out = indices.map(|i| {
1347+
// SAFETY: The base pointer is valid as it comes from a slice and the deref is always
1348+
// in-bounds as we've already checked the indices above.
1349+
#[allow(unsafe_code)]
1350+
unsafe {
1351+
(*(entries_ptr.add(i))).ref_mut()
1352+
}
1353+
});
1354+
1355+
Some(out)
1356+
}
1357+
12891358
/// Get the first key-value pair
12901359
///
12911360
/// Computes in **O(1)** time.

src/map/tests.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,3 +923,94 @@ move_index_oob!(test_move_index_out_of_bounds_0_10, 0, 10);
923923
move_index_oob!(test_move_index_out_of_bounds_0_max, 0, usize::MAX);
924924
move_index_oob!(test_move_index_out_of_bounds_10_0, 10, 0);
925925
move_index_oob!(test_move_index_out_of_bounds_max_0, usize::MAX, 0);
926+
927+
#[test]
928+
fn disjoint_mut_empty_map() {
929+
let mut map: RingMap<u32, u32> = RingMap::default();
930+
assert!(map.get_disjoint_mut([&0, &1, &2, &3]).is_none());
931+
}
932+
933+
#[test]
934+
fn disjoint_mut_empty_param() {
935+
let mut map: RingMap<u32, u32> = RingMap::default();
936+
map.insert(1, 10);
937+
assert!(map.get_disjoint_mut([] as [&u32; 0]).is_some());
938+
}
939+
940+
#[test]
941+
fn disjoint_mut_single_fail() {
942+
let mut map: RingMap<u32, u32> = RingMap::default();
943+
map.insert(1, 10);
944+
assert!(map.get_disjoint_mut([&0]).is_none());
945+
}
946+
947+
#[test]
948+
fn disjoint_mut_single_success() {
949+
let mut map: RingMap<u32, u32> = RingMap::default();
950+
map.insert(1, 10);
951+
assert_eq!(map.get_disjoint_mut([&1]), Some([&mut 10]));
952+
}
953+
954+
#[test]
955+
fn disjoint_mut_multi_success() {
956+
let mut map: RingMap<u32, u32> = RingMap::default();
957+
map.insert(1, 100);
958+
map.insert(2, 200);
959+
map.insert(3, 300);
960+
map.insert(4, 400);
961+
assert_eq!(map.get_disjoint_mut([&1, &2]), Some([&mut 100, &mut 200]));
962+
assert_eq!(map.get_disjoint_mut([&1, &3]), Some([&mut 100, &mut 300]));
963+
assert_eq!(
964+
map.get_disjoint_mut([&3, &1, &4, &2]),
965+
Some([&mut 300, &mut 100, &mut 400, &mut 200])
966+
);
967+
}
968+
969+
#[test]
970+
fn disjoint_mut_multi_success_unsized_key() {
971+
let mut map: RingMap<&'static str, u32> = RingMap::default();
972+
map.insert("1", 100);
973+
map.insert("2", 200);
974+
map.insert("3", 300);
975+
map.insert("4", 400);
976+
assert_eq!(map.get_disjoint_mut(["1", "2"]), Some([&mut 100, &mut 200]));
977+
assert_eq!(map.get_disjoint_mut(["1", "3"]), Some([&mut 100, &mut 300]));
978+
assert_eq!(
979+
map.get_disjoint_mut(["3", "1", "4", "2"]),
980+
Some([&mut 300, &mut 100, &mut 400, &mut 200])
981+
);
982+
}
983+
984+
#[test]
985+
fn disjoint_mut_multi_fail_missing() {
986+
let mut map: RingMap<u32, u32> = RingMap::default();
987+
map.insert(1, 10);
988+
map.insert(1123, 100);
989+
map.insert(321, 20);
990+
map.insert(1337, 30);
991+
assert_eq!(map.get_disjoint_mut([&121, &1123]), None);
992+
assert_eq!(map.get_disjoint_mut([&1, &1337, &56]), None);
993+
assert_eq!(map.get_disjoint_mut([&1337, &123, &321, &1, &1123]), None);
994+
}
995+
996+
#[test]
997+
fn disjoint_mut_multi_fail_duplicate() {
998+
let mut map: RingMap<u32, u32> = RingMap::default();
999+
map.insert(1, 10);
1000+
map.insert(1123, 100);
1001+
map.insert(321, 20);
1002+
map.insert(1337, 30);
1003+
assert_eq!(map.get_disjoint_mut([&1, &1]), None);
1004+
assert_eq!(
1005+
map.get_disjoint_mut([&1337, &123, &321, &1337, &1, &1123]),
1006+
None
1007+
);
1008+
}
1009+
1010+
#[test]
1011+
fn many_index_mut_fail_oob() {
1012+
let mut map: RingMap<u32, u32> = RingMap::default();
1013+
map.insert(1, 10);
1014+
map.insert(321, 20);
1015+
assert_eq!(map.get_disjoint_indices_mut([1, 3]), None);
1016+
}

0 commit comments

Comments
 (0)