diff --git a/lib.rs b/lib.rs index 3cfa797..0db0e39 100644 --- a/lib.rs +++ b/lib.rs @@ -650,6 +650,50 @@ impl SmallVec { } self.truncate(len - del); } + + /// Removes consecutive duplicate elements. + pub fn dedup(&mut self) where A::Item: PartialEq { + self.dedup_by(|a, b| a == b); + } + + /// Removes consecutive duplicate elements using the given equality relation. + pub fn dedup_by(&mut self, mut same_bucket: F) + where F: FnMut(&mut A::Item, &mut A::Item) -> bool + { + // See the implementation of Vec::dedup_by in the + // standard library for an explanation of this algorithm. + let len = self.len; + if len <= 1 { + return; + } + + let ptr = self.as_mut_ptr(); + let mut w: usize = 1; + + unsafe { + for r in 1..len { + let p_r = ptr.offset(r as isize); + let p_wm1 = ptr.offset((w - 1) as isize); + if !same_bucket(&mut *p_r, &mut *p_wm1) { + if r != w { + let p_w = p_wm1.offset(1); + mem::swap(&mut *p_r, &mut *p_w); + } + w += 1; + } + } + } + + self.truncate(w); + } + + /// Removes consecutive elements that map to the same key. + pub fn dedup_by_key(&mut self, mut key: F) + where F: FnMut(&mut A::Item) -> K, + K: PartialEq + { + self.dedup_by(|a, b| key(a) == key(b)); + } } impl SmallVec where A::Item: Copy { @@ -1683,6 +1727,25 @@ pub mod tests { assert_eq!(Rc::strong_count(&one), 1); } + #[test] + fn test_dedup() { + let mut dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 2, 3, 3]); + dupes.dedup(); + assert_eq!(&*dupes, &[1, 2, 3]); + + let mut empty: SmallVec<[i32; 5]> = SmallVec::new(); + empty.dedup(); + assert!(empty.is_empty()); + + let mut all_ones: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 1, 1, 1]); + all_ones.dedup(); + assert_eq!(all_ones.len(), 1); + + let mut no_dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 4, 5]); + no_dupes.dedup(); + assert_eq!(no_dupes.len(), 5); + } + #[cfg(feature = "std")] #[test] fn test_write() {