use std::cmp::Ordering;
use std::fmt::Debug;
pub(crate) trait VecExt<T> {
fn spare_capacity(&self) -> usize;
#[inline]
fn has_spare_capacity(&self) -> bool {
self.spare_capacity() != 0
}
unsafe fn push_unchecked(&mut self, elem: T);
fn is_sorted_by<F>(&self, compare: F) -> bool
where
F: FnMut(&T, &T) -> Option<Ordering>;
fn is_sorted_by_key<F, U>(&self, mut key: F) -> bool
where
F: FnMut(&T) -> U,
U: PartialOrd,
{
self.is_sorted_by(|a, b| key(a).partial_cmp(&key(b)))
}
}
impl<T> VecExt<T> for Vec<T>
where
T: Debug,
{
#[inline]
fn spare_capacity(&self) -> usize {
self.capacity() - self.len()
}
#[inline(always)]
unsafe fn push_unchecked(&mut self, elem: T) {
unsafe {
debug_assert_ne!(self.capacity(), 0, "cannot push to a vec of length zero");
debug_assert!(
self.len() < self.capacity(),
"cannot push to a vec without spare capacity",
);
let len = self.len();
self.spare_capacity_mut().get_unchecked_mut(0).write(elem);
self.set_len(len + 1);
}
}
fn is_sorted_by<F>(&self, mut compare: F) -> bool
where
F: FnMut(&T, &T) -> Option<Ordering>,
{
let mut iter = self.iter();
let mut last = match iter.next() {
Some(item) => item,
None => return true,
};
iter.all(move |current| {
if let Some(Ordering::Greater) | None = compare(last, current) {
return false;
}
last = current;
true
})
}
}
#[cfg(test)]
mod tests {
use crate::utils::VecExt;
#[test]
fn is_sorted_by() {
let x = vec![1, 2, 3, 4, 5, 6];
assert!(x.is_sorted_by(|a, b| a.partial_cmp(b)));
let x = vec![1, 2, 6, 3, 4, 5];
assert!(!x.is_sorted_by(|a, b| a.partial_cmp(b)));
}
#[test]
fn spare_capacity() {
let mut vec = Vec::with_capacity(0);
assert_eq!(vec.spare_capacity(), 0);
assert!(!vec.has_spare_capacity());
vec.reserve_exact(10);
assert_eq!(vec.spare_capacity(), 10);
assert!(vec.has_spare_capacity());
for i in 0..9 {
vec.push(i);
}
assert_eq!(vec.spare_capacity(), 1);
assert!(vec.has_spare_capacity());
vec.push(0);
assert_eq!(vec.spare_capacity(), 0);
assert!(!vec.has_spare_capacity());
}
#[test]
fn push_unchecked_1() {
let mut vec = Vec::with_capacity(1);
unsafe { vec.push_unchecked("something") };
assert_eq!(vec.len(), 1);
assert_eq!(vec.capacity(), 1);
assert_eq!(&vec, &["something"]);
}
#[test]
fn push_unchecked_100() {
let mut vec = Vec::with_capacity(100);
assert!(vec.is_empty());
for i in 0..100 {
unsafe { vec.push_unchecked(i) };
}
assert_eq!(vec.len(), 100);
assert_eq!(vec.capacity(), 100);
assert_eq!(vec, (0..100).collect::<Vec<_>>());
}
#[test]
#[cfg(debug_assertions)]
#[should_panic = "cannot push to a vec of length zero"]
fn push_unchecked_zero_capacity() {
let mut empty = Vec::with_capacity(0);
unsafe { empty.push_unchecked(false) };
}
#[test]
#[cfg(debug_assertions)]
#[should_panic = "cannot push to a vec without spare capacity"]
fn push_unchecked_full() {
let mut full = Vec::with_capacity(10);
for i in 0..10 {
full.push(i);
}
unsafe { full.push_unchecked(0) };
}
}