Skip to content

Commit b5ac29e

Browse files
authored
Merge pull request #160 from cuviper/more-vec
Add more Vec/slice-like methods to maps and sets
2 parents 59e2833 + 4819253 commit b5ac29e

File tree

4 files changed

+148
-3
lines changed

4 files changed

+148
-3
lines changed

src/map.rs

+59
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ impl<K, V, S> IndexMap<K, V, S> {
252252
self.core.clear();
253253
}
254254

255+
/// Shortens the map, keeping the first `len` elements and dropping the rest.
256+
///
257+
/// If `len` is greater than the map's current length, this has no effect.
258+
pub fn truncate(&mut self, len: usize) {
259+
self.core.truncate(len);
260+
}
261+
255262
/// Clears the `IndexMap` in the given index range, returning those
256263
/// key-value pairs as a drain iterator.
257264
///
@@ -273,6 +280,23 @@ impl<K, V, S> IndexMap<K, V, S> {
273280
iter: self.core.drain(range),
274281
}
275282
}
283+
284+
/// Splits the collection into two at the given index.
285+
///
286+
/// Returns a newly allocated map containing the elements in the range
287+
/// `[at, len)`. After the call, the original map will be left containing
288+
/// the elements `[0, at)` with its previous capacity unchanged.
289+
///
290+
/// ***Panics*** if `at > len`.
291+
pub fn split_off(&mut self, at: usize) -> Self
292+
where
293+
S: Clone,
294+
{
295+
Self {
296+
core: self.core.split_off(at),
297+
hash_builder: self.hash_builder.clone(),
298+
}
299+
}
276300
}
277301

278302
impl<K, V, S> IndexMap<K, V, S>
@@ -693,6 +717,34 @@ impl<K, V, S> IndexMap<K, V, S> {
693717
self.as_entries_mut().get_mut(index).map(Bucket::muts)
694718
}
695719

720+
/// Get the first key-value pair
721+
///
722+
/// Computes in **O(1)** time.
723+
pub fn first(&self) -> Option<(&K, &V)> {
724+
self.as_entries().first().map(Bucket::refs)
725+
}
726+
727+
/// Get the first key-value pair, with mutable access to the value
728+
///
729+
/// Computes in **O(1)** time.
730+
pub fn first_mut(&mut self) -> Option<(&K, &mut V)> {
731+
self.as_entries_mut().first_mut().map(Bucket::ref_mut)
732+
}
733+
734+
/// Get the last key-value pair
735+
///
736+
/// Computes in **O(1)** time.
737+
pub fn last(&self) -> Option<(&K, &V)> {
738+
self.as_entries().last().map(Bucket::refs)
739+
}
740+
741+
/// Get the last key-value pair, with mutable access to the value
742+
///
743+
/// Computes in **O(1)** time.
744+
pub fn last_mut(&mut self) -> Option<(&K, &mut V)> {
745+
self.as_entries_mut().last_mut().map(Bucket::ref_mut)
746+
}
747+
696748
/// Remove the key-value pair by index
697749
///
698750
/// Valid indices are *0 <= index < self.len()*
@@ -718,6 +770,13 @@ impl<K, V, S> IndexMap<K, V, S> {
718770
pub fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> {
719771
self.core.shift_remove_index(index)
720772
}
773+
774+
/// Swaps the position of two key-value pairs in the map.
775+
///
776+
/// ***Panics*** if `a` or `b` are out of bounds.
777+
pub fn swap_indices(&mut self, a: usize, b: usize) {
778+
self.core.swap_indices(a, b)
779+
}
721780
}
722781

723782
/// An iterator over the keys of a `IndexMap`.

src/map/core.rs

+19
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ impl<K, V> IndexMapCore<K, V> {
150150
self.entries.clear();
151151
}
152152

153+
pub(crate) fn truncate(&mut self, len: usize) {
154+
if len < self.len() {
155+
self.erase_indices(len, self.entries.len());
156+
self.entries.truncate(len);
157+
}
158+
}
159+
153160
pub(crate) fn drain<R>(&mut self, range: R) -> Drain<'_, Bucket<K, V>>
154161
where
155162
R: RangeBounds<usize>,
@@ -159,6 +166,18 @@ impl<K, V> IndexMapCore<K, V> {
159166
self.entries.drain(range)
160167
}
161168

169+
pub(crate) fn split_off(&mut self, at: usize) -> Self {
170+
assert!(at <= self.entries.len());
171+
self.erase_indices(at, self.entries.len());
172+
let entries = self.entries.split_off(at);
173+
174+
let mut indices = RawTable::with_capacity(entries.len());
175+
for (i, entry) in enumerate(&entries) {
176+
indices.insert_no_grow(entry.hash.get(), i);
177+
}
178+
Self { indices, entries }
179+
}
180+
162181
/// Reserve capacity for `additional` more key-value pairs.
163182
pub(crate) fn reserve(&mut self, additional: usize) {
164183
self.indices.reserve(additional, get_hash(&self.entries));

src/map/core/raw.rs

+23
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,29 @@ impl<K, V> IndexMapCore<K, V> {
6161
// only the item references that are appropriately bound to `&mut self`.
6262
unsafe { self.indices.iter().map(|bucket| bucket.as_mut()) }
6363
}
64+
65+
/// Return the raw bucket for the given index
66+
fn find_index(&self, index: usize) -> RawBucket {
67+
// We'll get a "nice" bounds-check from indexing `self.entries`,
68+
// and then we expect to find it in the table as well.
69+
let hash = self.entries[index].hash.get();
70+
self.indices
71+
.find(hash, move |&i| i == index)
72+
.expect("index not found")
73+
}
74+
75+
pub(crate) fn swap_indices(&mut self, a: usize, b: usize) {
76+
// SAFETY: Can't take two `get_mut` references from one table, so we
77+
// must use raw buckets to do the swap. This is still safe because we
78+
// are locally sure they won't dangle, and we write them individually.
79+
unsafe {
80+
let raw_bucket_a = self.find_index(a);
81+
let raw_bucket_b = self.find_index(b);
82+
raw_bucket_a.write(b);
83+
raw_bucket_b.write(a);
84+
}
85+
self.entries.swap(a, b);
86+
}
6487
}
6588

6689
/// A view into an occupied entry in a `IndexMap`.

src/set.rs

+47-3
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,13 @@ impl<T, S> IndexSet<T, S> {
200200
self.map.clear();
201201
}
202202

203+
/// Shortens the set, keeping the first `len` elements and dropping the rest.
204+
///
205+
/// If `len` is greater than the set's current length, this has no effect.
206+
pub fn truncate(&mut self, len: usize) {
207+
self.map.truncate(len);
208+
}
209+
203210
/// Clears the `IndexSet` in the given index range, returning those values
204211
/// as a drain iterator.
205212
///
@@ -221,6 +228,22 @@ impl<T, S> IndexSet<T, S> {
221228
iter: self.map.drain(range).iter,
222229
}
223230
}
231+
232+
/// Splits the collection into two at the given index.
233+
///
234+
/// Returns a newly allocated set containing the elements in the range
235+
/// `[at, len)`. After the call, the original set will be left containing
236+
/// the elements `[0, at)` with its previous capacity unchanged.
237+
///
238+
/// ***Panics*** if `at > len`.
239+
pub fn split_off(&mut self, at: usize) -> Self
240+
where
241+
S: Clone,
242+
{
243+
Self {
244+
map: self.map.split_off(at),
245+
}
246+
}
224247
}
225248

226249
impl<T, S> IndexSet<T, S>
@@ -576,10 +599,24 @@ impl<T, S> IndexSet<T, S> {
576599
///
577600
/// Computes in **O(1)** time.
578601
pub fn get_index(&self, index: usize) -> Option<&T> {
579-
self.map.get_index(index).map(|(x, &())| x)
602+
self.as_entries().get(index).map(Bucket::key_ref)
580603
}
581604

582-
/// Remove the key-value pair by index
605+
/// Get the first value
606+
///
607+
/// Computes in **O(1)** time.
608+
pub fn first(&self) -> Option<&T> {
609+
self.as_entries().first().map(Bucket::key_ref)
610+
}
611+
612+
/// Get the last value
613+
///
614+
/// Computes in **O(1)** time.
615+
pub fn last(&self) -> Option<&T> {
616+
self.as_entries().last().map(Bucket::key_ref)
617+
}
618+
619+
/// Remove the value by index
583620
///
584621
/// Valid indices are *0 <= index < self.len()*
585622
///
@@ -592,7 +629,7 @@ impl<T, S> IndexSet<T, S> {
592629
self.map.swap_remove_index(index).map(|(x, ())| x)
593630
}
594631

595-
/// Remove the key-value pair by index
632+
/// Remove the value by index
596633
///
597634
/// Valid indices are *0 <= index < self.len()*
598635
///
@@ -604,6 +641,13 @@ impl<T, S> IndexSet<T, S> {
604641
pub fn shift_remove_index(&mut self, index: usize) -> Option<T> {
605642
self.map.shift_remove_index(index).map(|(x, ())| x)
606643
}
644+
645+
/// Swaps the position of two values in the set.
646+
///
647+
/// ***Panics*** if `a` or `b` are out of bounds.
648+
pub fn swap_indices(&mut self, a: usize, b: usize) {
649+
self.map.swap_indices(a, b)
650+
}
607651
}
608652

609653
/// Access `IndexSet` values at indexed positions.

0 commit comments

Comments
 (0)