Skip to content

Commit c2ffd3d

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 <[email protected]>
1 parent e79f79c commit c2ffd3d

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99
- Added `from_bytes_truncating_at_nul` to `CString`
10+
- Added `remove_insert` to `Vec`
1011

1112
## [v0.9.2] 2025-11-12
1213

src/vec/mod.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,56 @@ 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 to_remove = ptr::read(self.as_ptr().add(remove_index));
996+
997+
match remove_index.cmp(&insert_index) {
998+
Ordering::Equal => (),
999+
Ordering::Less => {
1000+
let remove_at = self.as_mut_ptr().add(remove_index);
1001+
ptr::copy(remove_at.add(1), remove_at, insert_index - remove_index);
1002+
}
1003+
Ordering::Greater => {
1004+
let insert_at = self.as_mut_ptr().add(insert_index);
1005+
ptr::copy(insert_at, insert_at.add(1), remove_index - insert_index);
1006+
}
1007+
}
1008+
ptr::write(self.as_mut_ptr().add(insert_index), element);
1009+
to_remove
1010+
}
1011+
}
1012+
9631013
/// Returns true if the vec is full
9641014
pub fn is_full(&self) -> bool {
9651015
self.len() == self.capacity()
@@ -2119,6 +2169,92 @@ mod tests {
21192169
assert_eq!(v.len(), 0);
21202170
}
21212171

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

0 commit comments

Comments
 (0)