From 4e376d0b4a4a9768b0ab3cee087505afa647c2f3 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 7 Jan 2026 17:01:03 -0800 Subject: [PATCH] Add range methods to `RingMap` and `RingSet` ``` impl RingMap { pub fn range(&self, range: R) -> Iter<'_, K, V>; pub fn range_mut(&mut self, range: R) -> IterMut<'_, K, V>; pub fn get_range(&self, range: R) -> Option<(&Slice, &Slice)>; pub fn get_range_mut(&mut self, range: R) -> Option<(&mut Slice, &mut Slice)>; } impl RingSet { pub fn range(&self, range: R) -> Iter<'_, T>; pub fn get_range(&self, range: R) -> Option<(&Slice, &Slice)>; } ``` All of these are bounded `where R: RangeBounds` too. Note that the `get_range` and `get_range_mut` methods are similar to `indexmap`, as well as our existing `Slice` methods, except here we need to return a pair of slices. The `range` and `range_mut` methods are more like those on `VecDeque`, where you don't have to worry about the head+tail pair yourself. --- src/map.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++-- src/map/iter.rs | 46 ++++++++++++++++--------- src/set.rs | 31 ++++++++++++++++- src/set/iter.rs | 6 ++++ 4 files changed, 153 insertions(+), 19 deletions(-) diff --git a/src/map.rs b/src/map.rs index 302b8d4..fa2efcc 100644 --- a/src/map.rs +++ b/src/map.rs @@ -39,13 +39,13 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{BuildHasher, Hash, Hasher}; use core::mem; -use core::ops::{Index, IndexMut, RangeBounds}; +use core::ops::{Index, IndexMut, Range, RangeBounds}; #[cfg(feature = "std")] use std::hash::RandomState; use crate::inner::Core; -use crate::util::third; +use crate::util::{simplify_range, third, try_simplify_range}; use crate::{Bucket, Equivalent, GetDisjointMutError, HashValue, TryReserveError}; /// A hash table where the iteration order of the key-value pairs is independent @@ -1591,6 +1591,91 @@ impl RingMap { Ok(key_values.map(Option::unwrap)) } + #[track_caller] + pub(crate) fn split_range(&self, range: R) -> (Range, Range) + where + R: RangeBounds, + { + let entries = self.as_entries(); + let range = simplify_range(range, entries.len()); + let mid = entries.as_slices().0.len(); + ( + range.start.min(mid)..range.end.min(mid), + range.start.saturating_sub(mid)..range.end.saturating_sub(mid), + ) + } + + /// Returns an iterator of key-value pairs in the given range of indices. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the map. + #[track_caller] + pub fn range(&self, range: R) -> Iter<'_, K, V> + where + R: RangeBounds, + { + let (head_range, tail_range) = self.split_range(range); + let (head, tail) = self.as_entries().as_slices(); + Iter::from_slices(&head[head_range], &tail[tail_range]) + } + + /// Returns a mutable iterator of key-value pairs in the given range of indices. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the map. + #[track_caller] + pub fn range_mut(&mut self, range: R) -> IterMut<'_, K, V> + where + R: RangeBounds, + { + let (head_range, tail_range) = self.split_range(range); + let (head, tail) = self.as_entries_mut().as_mut_slices(); + IterMut::from_mut_slices(&mut head[head_range], &mut tail[tail_range]) + } + + pub(crate) fn try_split_range(&self, range: R) -> Option<(Range, Range)> + where + R: RangeBounds, + { + let entries = self.as_entries(); + let range = try_simplify_range(range, entries.len())?; + let mid = entries.as_slices().0.len(); + Some(( + range.start.min(mid)..range.end.min(mid), + range.start.saturating_sub(mid)..range.end.saturating_sub(mid), + )) + } + + /// Returns head and tail slices of key-value pairs in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_range(&self, range: R) -> Option<(&Slice, &Slice)> + where + R: RangeBounds, + { + let (head_range, tail_range) = self.try_split_range(range)?; + let (head, tail) = self.as_entries().as_slices(); + Some(( + Slice::from_slice(&head[head_range]), + Slice::from_slice(&tail[tail_range]), + )) + } + + /// Returns mutable head and tail slices of key-value pairs in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_range_mut(&mut self, range: R) -> Option<(&mut Slice, &mut Slice)> + where + R: RangeBounds, + { + let (head_range, tail_range) = self.try_split_range(range)?; + let (head, tail) = self.as_entries_mut().as_mut_slices(); + Some(( + Slice::from_mut_slice(&mut head[head_range]), + Slice::from_mut_slice(&mut tail[tail_range]), + )) + } + /// Get the first key-value pair /// /// Computes in **O(1)** time. diff --git a/src/map/iter.rs b/src/map/iter.rs index fded668..e215a0f 100644 --- a/src/map/iter.rs +++ b/src/map/iter.rs @@ -43,16 +43,17 @@ pub(crate) struct Buckets<'a, K, V> { impl<'a, K, V> Buckets<'a, K, V> { pub(crate) fn new(entries: &'a VecDeque>) -> Self { let (head, tail) = entries.as_slices(); - Self { - head: head.iter(), - tail: tail.iter(), - } + Self::from_slices(head, tail) } pub(crate) fn from_slice(slice: &'a [Bucket]) -> Self { + Self::from_slices(slice, &[]) + } + + pub(crate) fn from_slices(head: &'a [Bucket], tail: &'a [Bucket]) -> Self { Self { - head: slice.iter(), - tail: [].iter(), + head: head.iter(), + tail: tail.iter(), } } } @@ -174,24 +175,22 @@ struct BucketsMut<'a, K, V> { impl<'a, K, V> BucketsMut<'a, K, V> { fn new(entries: &'a mut VecDeque>) -> Self { let (head, tail) = entries.as_mut_slices(); - Self { - head: head.iter_mut(), - tail: tail.iter_mut(), - } + Self::from_mut_slices(head, tail) } fn from_mut_slice(slice: &'a mut [Bucket]) -> Self { + Self::from_mut_slices(slice, &mut []) + } + + fn from_mut_slices(head: &'a mut [Bucket], tail: &'a mut [Bucket]) -> Self { Self { - head: slice.iter_mut(), - tail: [].iter_mut(), + head: head.iter_mut(), + tail: tail.iter_mut(), } } fn iter(&self) -> Buckets<'_, K, V> { - Buckets { - head: self.head.as_slice().iter(), - tail: self.tail.as_slice().iter(), - } + Buckets::from_slices(self.head.as_slice(), self.tail.as_slice()) } } @@ -314,6 +313,12 @@ impl<'a, K, V> Iter<'a, K, V> { iter: Buckets::from_slice(slice), } } + + pub(super) fn from_slices(head: &'a [Bucket], tail: &'a [Bucket]) -> Self { + Self { + iter: Buckets::from_slices(head, tail), + } + } } impl<'a, K, V> Iterator for Iter<'a, K, V> { @@ -377,6 +382,15 @@ impl<'a, K, V> IterMut<'a, K, V> { iter: BucketsMut::from_mut_slice(slice), } } + + pub(super) fn from_mut_slices( + head: &'a mut [Bucket], + tail: &'a mut [Bucket], + ) -> Self { + Self { + iter: BucketsMut::from_mut_slices(head, tail), + } + } } impl<'a, K, V> Iterator for IterMut<'a, K, V> { diff --git a/src/set.rs b/src/set.rs index 050f8ac..9967e34 100644 --- a/src/set.rs +++ b/src/set.rs @@ -64,7 +64,7 @@ type Bucket = super::Bucket; /// /// # Complexity /// -/// Internally, `RingSet` just holds an [`RingMap`](RingMap). Thus the complexity +/// Internally, `RingSet` just holds a [`RingMap`](RingMap). Thus the complexity /// of the two are the same for most methods. /// /// # Examples @@ -1270,6 +1270,35 @@ impl RingSet { self.as_entries().get(index).map(Bucket::key_ref) } + /// Returns an iterator of values in the given range of indices. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the set. + #[track_caller] + pub fn range(&self, range: R) -> Iter<'_, T> + where + R: RangeBounds, + { + let (head_range, tail_range) = self.map.split_range(range); + let (head, tail) = self.as_entries().as_slices(); + Iter::from_slices(&head[head_range], &tail[tail_range]) + } + + /// Returns head and tail slices of values in the given range of indices. + /// + /// Valid indices are `0 <= index < self.len()`. + pub fn get_range(&self, range: R) -> Option<(&Slice, &Slice)> + where + R: RangeBounds, + { + let (head_range, tail_range) = self.map.try_split_range(range)?; + let (head, tail) = self.as_entries().as_slices(); + Some(( + Slice::from_slice(&head[head_range]), + Slice::from_slice(&tail[tail_range]), + )) + } + /// Get the first value /// /// Computes in **O(1)** time. diff --git a/src/set/iter.rs b/src/set/iter.rs index 17ceb01..aa9506f 100644 --- a/src/set/iter.rs +++ b/src/set/iter.rs @@ -48,6 +48,12 @@ impl<'a, T> Iter<'a, T> { iter: Buckets::from_slice(slice), } } + + pub(super) fn from_slices(head: &'a [Bucket], tail: &'a [Bucket]) -> Self { + Self { + iter: Buckets::from_slices(head, tail), + } + } } impl<'a, T> Iterator for Iter<'a, T> {