Skip to content

Commit 4a0de07

Browse files
committed
Add Vec::remove_insert()
In patterns where an insertion directly follows a removal, this serves as being more efficient, since it only shifts/copies values as needed for the combined operation. This also comes with the added bonus of not needing to check for fullness, and thus, a `Result` is not needed as a return type. Signed-off-by: Mohammad AlSaleh <CE.Mohammad.AlSaleh@gmail.com>
1 parent e79f79c commit 4a0de07

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

src/vec/mod.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,57 @@ impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> VecInner<T, LenT, S> {
960960
value
961961
}
962962

963+
/// This is the same as calling [`Vec::remove`] with `remove_index`
964+
/// followed by calling [`Vec::insert`] with `insert_index` and `element`.
965+
///
966+
/// The returned value is the removed element.
967+
///
968+
/// This is more efficient than removing then inserting since it only shifts
969+
/// `remove_index.abs_diff(insert_index)` values.
970+
///
971+
/// [`remove`]: Vec::remove
972+
/// [`insert`]: Vec::insert
973+
///
974+
/// # Panics
975+
///
976+
/// Panics if `remove_index` or `insert_index` are out of bounds.
977+
///
978+
/// # Examples
979+
///
980+
/// ```
981+
/// use heapless::Vec;
982+
///
983+
/// let mut v: Vec<_, 8> = Vec::from_slice(&[0, 1, 2, 3]).unwrap();
984+
/// assert_eq!(v.remove_insert(1, 2, 4), 1);
985+
/// // only one element (2) is shifted back
986+
/// assert_eq!(v, [0, 2, 4, 3]);
987+
/// ```
988+
pub fn remove_insert(&mut self, remove_index: usize, insert_index: usize, element: T) -> T {
989+
let length = self.len();
990+
991+
assert!(remove_index < length);
992+
assert!(insert_index < length);
993+
994+
unsafe {
995+
let remove_at = self.as_mut_ptr().add(remove_index);
996+
let insert_at = self.as_mut_ptr().add(insert_index);
997+
998+
let to_remove = ptr::read(remove_at);
999+
1000+
match remove_index.cmp(&insert_index) {
1001+
Ordering::Equal => (),
1002+
Ordering::Less => {
1003+
ptr::copy(remove_at.add(1), remove_at, insert_index - remove_index);
1004+
}
1005+
Ordering::Greater => {
1006+
ptr::copy(insert_at, insert_at.add(1), remove_index - insert_index);
1007+
}
1008+
}
1009+
ptr::write(insert_at, element);
1010+
to_remove
1011+
}
1012+
}
1013+
9631014
/// Returns true if the vec is full
9641015
pub fn is_full(&self) -> bool {
9651016
self.len() == self.capacity()
@@ -2119,6 +2170,92 @@ mod tests {
21192170
assert_eq!(v.len(), 0);
21202171
}
21212172

2173+
#[test]
2174+
fn remove_insert() {
2175+
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
2176+
let mut v: Vec<u8, 10> = Vec::from_array(arr);
2177+
let mut v2: Vec<u8, 10> = Vec::from_array(arr);
2178+
2179+
// insert_index == remove_index
2180+
let n = v.remove_insert(2, 2, 10);
2181+
assert_eq!(n, 2);
2182+
assert_eq!(v, [0, 1, 10, 3, 4, 5, 6, 7, 8, 9]);
2183+
2184+
let n2 = v2.remove(2);
2185+
v2.insert(2, 10).unwrap();
2186+
assert_eq!(n, n2);
2187+
assert_eq!(v, v2);
2188+
2189+
// reset
2190+
v.copy_from_slice(&arr);
2191+
v2.copy_from_slice(&arr);
2192+
2193+
// insert_index > remove_index
2194+
let n = v.remove_insert(3, 5, 10);
2195+
assert_eq!(n, 3);
2196+
assert_eq!(v, [0, 1, 2, 4, 5, 10, 6, 7, 8, 9]);
2197+
2198+
let n2 = v2.remove(3);
2199+
v2.insert(5, 10).unwrap();
2200+
assert_eq!(n, n2);
2201+
assert_eq!(v, v2);
2202+
2203+
v.copy_from_slice(&arr);
2204+
v2.copy_from_slice(&arr);
2205+
2206+
// insert_index < remove_index
2207+
let n = v.remove_insert(5, 3, 10);
2208+
assert_eq!(n, 5);
2209+
assert_eq!(v, [0, 1, 2, 10, 3, 4, 6, 7, 8, 9]);
2210+
2211+
let n2 = v2.remove(5);
2212+
v2.insert(3, 10).unwrap();
2213+
2214+
assert_eq!(n, n2);
2215+
assert_eq!(v, v2);
2216+
2217+
// at boundaries
2218+
2219+
v.copy_from_slice(&arr);
2220+
v2.copy_from_slice(&arr);
2221+
2222+
let n = v.remove_insert(0, 9, 10);
2223+
assert_eq!(n, 0);
2224+
assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
2225+
2226+
let n2 = v2.remove(0);
2227+
v2.insert(9, 10).unwrap();
2228+
assert_eq!(n, n2);
2229+
assert_eq!(v, v2);
2230+
2231+
v.copy_from_slice(&arr);
2232+
v2.copy_from_slice(&arr);
2233+
2234+
let n = v.remove_insert(9, 0, 10);
2235+
assert_eq!(n, 9);
2236+
assert_eq!(v, [10, 0, 1, 2, 3, 4, 5, 6, 7, 8]);
2237+
2238+
let n2 = v2.remove(9);
2239+
v2.insert(0, 10).unwrap();
2240+
assert_eq!(n, n2);
2241+
assert_eq!(v, v2);
2242+
}
2243+
2244+
#[test]
2245+
#[should_panic]
2246+
fn remove_insert_out_of_bounds() {
2247+
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
2248+
let mut v: Vec<u8, 10> = Vec::from_array(arr);
2249+
let _ = v.remove_insert(0, 10, 10);
2250+
}
2251+
2252+
#[test]
2253+
#[should_panic]
2254+
fn remove_insert_empty() {
2255+
let mut v: Vec<u8, 10> = Vec::from_array([]);
2256+
let _ = v.remove_insert(0, 0, 10);
2257+
}
2258+
21222259
#[test]
21232260
fn resize_size_limit() {
21242261
let mut v: Vec<u8, 4> = Vec::new();

0 commit comments

Comments
 (0)