Skip to content

Commit 8c329c3

Browse files
bors[bot]Dirbaio
andauthored
Merge #301
301: Add some more Vec methods. r=japaric a=Dirbaio Added - `Vec::insert(index, element)` - `Vec::remove(index)` - `Vec::retain(f)` - `Vec::retain_mut(f)` Behavior matches `std` except `insert` which is now fallible and returns back the element when full. Implementation and docs taken from `std`. Co-authored-by: Dario Nieuwenhuis <[email protected]>
2 parents 344629e + 1d4c333 commit 8c329c3

File tree

2 files changed

+261
-0
lines changed

2 files changed

+261
-0
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- Added `Vec::insert(index, element)`
13+
- Added `Vec::remove(index)`
14+
- Added `Vec::retain(f)`
15+
- Added `Vec::retain_mut(f)`
16+
1217
### Changed
1318

1419
### Fixed

src/vec.rs

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,262 @@ impl<T, const N: usize> Vec<T, N> {
567567
let (v, n) = (self.len(), needle.len());
568568
v >= n && needle == &self[v - n..]
569569
}
570+
571+
/// Inserts an element at position `index` within the vector, shifting all
572+
/// elements after it to the right.
573+
///
574+
/// Returns back the `element` if the vector is full.
575+
///
576+
/// # Panics
577+
///
578+
/// Panics if `index > len`.
579+
///
580+
/// # Examples
581+
///
582+
/// ```
583+
/// use heapless::Vec;
584+
///
585+
/// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3]).unwrap();
586+
/// vec.insert(1, 4);
587+
/// assert_eq!(vec, [1, 4, 2, 3]);
588+
/// vec.insert(4, 5);
589+
/// assert_eq!(vec, [1, 4, 2, 3, 5]);
590+
/// ```
591+
pub fn insert(&mut self, index: usize, element: T) -> Result<(), T> {
592+
let len = self.len();
593+
if index > len {
594+
panic!(
595+
"insertion index (is {}) should be <= len (is {})",
596+
index, len
597+
);
598+
}
599+
600+
// check there's space for the new element
601+
if self.is_full() {
602+
return Err(element);
603+
}
604+
605+
unsafe {
606+
// infallible
607+
// The spot to put the new value
608+
{
609+
let p = self.as_mut_ptr().add(index);
610+
// Shift everything over to make space. (Duplicating the
611+
// `index`th element into two consecutive places.)
612+
ptr::copy(p, p.offset(1), len - index);
613+
// Write it in, overwriting the first copy of the `index`th
614+
// element.
615+
ptr::write(p, element);
616+
}
617+
self.set_len(len + 1);
618+
}
619+
620+
Ok(())
621+
}
622+
623+
/// Removes and returns the element at position `index` within the vector,
624+
/// shifting all elements after it to the left.
625+
///
626+
/// Note: Because this shifts over the remaining elements, it has a
627+
/// worst-case performance of *O*(*n*). If you don't need the order of elements
628+
/// to be preserved, use [`swap_remove`] instead. If you'd like to remove
629+
/// elements from the beginning of the `Vec`, consider using
630+
/// [`VecDeque::pop_front`] instead.
631+
///
632+
/// [`swap_remove`]: Vec::swap_remove
633+
/// [`VecDeque::pop_front`]: crate::VecDeque::pop_front
634+
///
635+
/// # Panics
636+
///
637+
/// Panics if `index` is out of bounds.
638+
///
639+
/// # Examples
640+
///
641+
/// ```
642+
/// use heapless::Vec;
643+
///
644+
/// let mut v: Vec<_, 8> = Vec::from_slice(&[1, 2, 3]).unwrap();
645+
/// assert_eq!(v.remove(1), 2);
646+
/// assert_eq!(v, [1, 3]);
647+
/// ```
648+
pub fn remove(&mut self, index: usize) -> T {
649+
let len = self.len();
650+
if index >= len {
651+
panic!("removal index (is {}) should be < len (is {})", index, len);
652+
}
653+
unsafe {
654+
// infallible
655+
let ret;
656+
{
657+
// the place we are taking from.
658+
let ptr = self.as_mut_ptr().add(index);
659+
// copy it out, unsafely having a copy of the value on
660+
// the stack and in the vector at the same time.
661+
ret = ptr::read(ptr);
662+
663+
// Shift everything down to fill in that spot.
664+
ptr::copy(ptr.offset(1), ptr, len - index - 1);
665+
}
666+
self.set_len(len - 1);
667+
ret
668+
}
669+
}
670+
671+
/// Retains only the elements specified by the predicate.
672+
///
673+
/// In other words, remove all elements `e` for which `f(&e)` returns `false`.
674+
/// This method operates in place, visiting each element exactly once in the
675+
/// original order, and preserves the order of the retained elements.
676+
///
677+
/// # Examples
678+
///
679+
/// ```
680+
/// use heapless::Vec;
681+
///
682+
/// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
683+
/// vec.retain(|&x| x % 2 == 0);
684+
/// assert_eq!(vec, [2, 4]);
685+
/// ```
686+
///
687+
/// Because the elements are visited exactly once in the original order,
688+
/// external state may be used to decide which elements to keep.
689+
///
690+
/// ```
691+
/// use heapless::Vec;
692+
///
693+
/// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4, 5]).unwrap();
694+
/// let keep = [false, true, true, false, true];
695+
/// let mut iter = keep.iter();
696+
/// vec.retain(|_| *iter.next().unwrap());
697+
/// assert_eq!(vec, [2, 3, 5]);
698+
/// ```
699+
pub fn retain<F>(&mut self, mut f: F)
700+
where
701+
F: FnMut(&T) -> bool,
702+
{
703+
self.retain_mut(|elem| f(elem));
704+
}
705+
706+
/// Retains only the elements specified by the predicate, passing a mutable reference to it.
707+
///
708+
/// In other words, remove all elements `e` such that `f(&mut e)` returns `false`.
709+
/// This method operates in place, visiting each element exactly once in the
710+
/// original order, and preserves the order of the retained elements.
711+
///
712+
/// # Examples
713+
///
714+
/// ```
715+
/// use heapless::Vec;
716+
///
717+
/// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4]).unwrap();
718+
/// vec.retain_mut(|x| if *x <= 3 {
719+
/// *x += 1;
720+
/// true
721+
/// } else {
722+
/// false
723+
/// });
724+
/// assert_eq!(vec, [2, 3, 4]);
725+
/// ```
726+
pub fn retain_mut<F>(&mut self, mut f: F)
727+
where
728+
F: FnMut(&mut T) -> bool,
729+
{
730+
let original_len = self.len();
731+
// Avoid double drop if the drop guard is not executed,
732+
// since we may make some holes during the process.
733+
unsafe { self.set_len(0) };
734+
735+
// Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked]
736+
// |<- processed len ->| ^- next to check
737+
// |<- deleted cnt ->|
738+
// |<- original_len ->|
739+
// Kept: Elements which predicate returns true on.
740+
// Hole: Moved or dropped element slot.
741+
// Unchecked: Unchecked valid elements.
742+
//
743+
// This drop guard will be invoked when predicate or `drop` of element panicked.
744+
// It shifts unchecked elements to cover holes and `set_len` to the correct length.
745+
// In cases when predicate and `drop` never panick, it will be optimized out.
746+
struct BackshiftOnDrop<'a, T, const N: usize> {
747+
v: &'a mut Vec<T, N>,
748+
processed_len: usize,
749+
deleted_cnt: usize,
750+
original_len: usize,
751+
}
752+
753+
impl<T, const N: usize> Drop for BackshiftOnDrop<'_, T, N> {
754+
fn drop(&mut self) {
755+
if self.deleted_cnt > 0 {
756+
// SAFETY: Trailing unchecked items must be valid since we never touch them.
757+
unsafe {
758+
ptr::copy(
759+
self.v.as_ptr().add(self.processed_len),
760+
self.v
761+
.as_mut_ptr()
762+
.add(self.processed_len - self.deleted_cnt),
763+
self.original_len - self.processed_len,
764+
);
765+
}
766+
}
767+
// SAFETY: After filling holes, all items are in contiguous memory.
768+
unsafe {
769+
self.v.set_len(self.original_len - self.deleted_cnt);
770+
}
771+
}
772+
}
773+
774+
let mut g = BackshiftOnDrop {
775+
v: self,
776+
processed_len: 0,
777+
deleted_cnt: 0,
778+
original_len,
779+
};
780+
781+
fn process_loop<F, T, const N: usize, const DELETED: bool>(
782+
original_len: usize,
783+
f: &mut F,
784+
g: &mut BackshiftOnDrop<'_, T, N>,
785+
) where
786+
F: FnMut(&mut T) -> bool,
787+
{
788+
while g.processed_len != original_len {
789+
let p = g.v.as_mut_ptr();
790+
// SAFETY: Unchecked element must be valid.
791+
let cur = unsafe { &mut *p.add(g.processed_len) };
792+
if !f(cur) {
793+
// Advance early to avoid double drop if `drop_in_place` panicked.
794+
g.processed_len += 1;
795+
g.deleted_cnt += 1;
796+
// SAFETY: We never touch this element again after dropped.
797+
unsafe { ptr::drop_in_place(cur) };
798+
// We already advanced the counter.
799+
if DELETED {
800+
continue;
801+
} else {
802+
break;
803+
}
804+
}
805+
if DELETED {
806+
// SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element.
807+
// We use copy for move, and never touch this element again.
808+
unsafe {
809+
let hole_slot = p.add(g.processed_len - g.deleted_cnt);
810+
ptr::copy_nonoverlapping(cur, hole_slot, 1);
811+
}
812+
}
813+
g.processed_len += 1;
814+
}
815+
}
816+
817+
// Stage 1: Nothing was deleted.
818+
process_loop::<F, T, N, false>(original_len, &mut f, &mut g);
819+
820+
// Stage 2: Some elements were deleted.
821+
process_loop::<F, T, N, true>(original_len, &mut f, &mut g);
822+
823+
// All item are processed. This can be optimized to `set_len` by LLVM.
824+
drop(g);
825+
}
570826
}
571827

572828
// Trait implementations

0 commit comments

Comments
 (0)