blob: ba429b0a488685129c3c990752454e865271cc83 [file] [edit]
// Copyright © 2022 Collabora, Ltd.
// SPDX-License-Identifier: MIT
#[derive(Clone, Default)]
enum SmallVecImpl<T> {
#[default]
None,
One(T),
Many(Vec<T>),
}
/// `SmallVec` is an optimized data structure that handles collections of items.
/// It is designed to avoid allocating a `Vec` unless multiple items are present.
///
/// # Variants
///
/// * `None` - Represents an empty collection, no items are stored.
/// * `One(T)` - Stores a single item without allocating a `Vec`.
/// * `Many(Vec<T>)` - Stores multiple items in a heap-allocated `Vec`.
///
/// This helps to reduce the amount of Vec's allocated in the optimization passes.
#[derive(Clone)]
pub struct SmallVec<T>(SmallVecImpl<T>);
// We can't use #[derive(Default)] here because it's not quite smart enough.
// It requires Default to be implemented for T, even though our default enum
// value is None, which doesn't care about the type T.
impl<T> Default for SmallVec<T> {
fn default() -> Self {
SmallVec(Default::default())
}
}
impl<T> SmallVec<T> {
/// Constructs a new, empty `SmallVec`
pub fn new() -> SmallVec<T> {
SmallVec(Default::default())
}
/// Adds an item to the `SmallVec`.
///
/// # Arguments
///
/// * `item` - The item to be added.
///
/// # Example
///
/// ```
/// let mut vec: SmallVec<String> = SmallVec::new();
/// vec.push("Hello".to_string());
/// vec.push("World".to_string());
/// ```
pub fn push(&mut self, i: T) {
self.push_mut(i);
}
/// Adds an item to the `SmallVec`, returning a reference to it.
///
/// # Arguments
///
/// * `item` - The item to be added.
///
/// # Example
///
/// ```
/// let mut vec: SmallVec<String> = SmallVec::new();
/// let item = vec.push_mut("Hello".to_string());
/// *item += "World";
/// ```
pub fn push_mut(&mut self, i: T) -> &mut T {
// Explicitly borrow once here so we don't confuse the borrow checker
// thinking self.0 gets mutably borrowed multiple times.
let imp = &mut self.0;
match imp {
SmallVecImpl::None => {
*imp = SmallVecImpl::One(i);
match imp {
SmallVecImpl::One(i) => i,
_ => panic!("Not a One"),
}
}
SmallVecImpl::One(_) => {
*imp = match std::mem::take(imp) {
SmallVecImpl::One(o) => SmallVecImpl::Many(vec![o, i]),
_ => panic!("Not a One"),
};
match imp {
SmallVecImpl::Many(v) => v.last_mut().unwrap(),
_ => panic!("Not a Many"),
}
}
SmallVecImpl::Many(v) => {
// TODO: Replace with v.push_mut() when we update to
// Rust 1.95.0 or newer.
v.push(i);
v.last_mut().unwrap()
}
}
}
}
impl<T> std::ops::Deref for SmallVec<T> {
type Target = [T];
fn deref(&self) -> &[T] {
match &self.0 {
SmallVecImpl::None => &[],
SmallVecImpl::One(i) => std::slice::from_ref(i),
SmallVecImpl::Many(v) => v,
}
}
}
impl<T> std::ops::DerefMut for SmallVec<T> {
fn deref_mut(&mut self) -> &mut [T] {
match &mut self.0 {
SmallVecImpl::None => &mut [],
SmallVecImpl::One(i) => std::slice::from_mut(i),
SmallVecImpl::Many(v) => v,
}
}
}
impl<T> Extend<T> for SmallVec<T> {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
let mut iter = iter.into_iter();
loop {
match &mut self.0 {
SmallVecImpl::None | SmallVecImpl::One(_) => {
if let Some(i) = iter.next() {
self.push(i);
} else {
// We ran out of items
return;
}
}
SmallVecImpl::Many(v) => {
v.extend(iter);
return;
}
}
}
}
}
impl<T> From<Vec<T>> for SmallVec<T> {
fn from(v: Vec<T>) -> SmallVec<T> {
if v.is_empty() {
SmallVec(SmallVecImpl::None)
} else if v.len() == 1 {
// Hopefully, Rust can fold away most of this based on the
// `v.len() == 1` check above.
SmallVec(SmallVecImpl::One(v.into_iter().next().unwrap()))
} else {
SmallVec(SmallVecImpl::Many(v))
}
}
}
impl<T, const N: usize> From<[T; N]> for SmallVec<T> {
fn from(i: [T; N]) -> SmallVec<T> {
i.into_iter().collect()
}
}
impl<T> FromIterator<T> for SmallVec<T> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
let mut iter = iter.into_iter();
let Some(x) = iter.next() else {
return SmallVec(SmallVecImpl::None);
};
let Some(y) = iter.next() else {
return SmallVec(SmallVecImpl::One(x));
};
SmallVec(SmallVecImpl::Many([x, y].into_iter().chain(iter).collect()))
}
}
impl<T> From<SmallVec<T>> for Vec<T> {
fn from(sv: SmallVec<T>) -> Vec<T> {
match sv.0 {
SmallVecImpl::None => Vec::new(),
SmallVecImpl::One(i) => vec![i],
SmallVecImpl::Many(v) => v,
}
}
}
enum IntoIterImpl<T> {
None,
One(T),
Many(std::vec::IntoIter<T>),
}
pub struct IntoIter<T>(IntoIterImpl<T>);
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
IntoIterImpl::None => None,
IntoIterImpl::One(_) => {
match std::mem::replace(&mut self.0, IntoIterImpl::None) {
IntoIterImpl::One(i) => Some(i),
_ => panic!("Not a One"),
}
}
IntoIterImpl::Many(vi) => vi.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.0 {
IntoIterImpl::None => (0, Some(0)),
IntoIterImpl::One(_) => (1, Some(1)),
IntoIterImpl::Many(vi) => vi.size_hint(),
}
}
}
impl<T> std::iter::ExactSizeIterator for IntoIter<T> {}
impl<T> std::iter::FusedIterator for IntoIter<T> {}
impl<T> IntoIterator for SmallVec<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
let imp = match self.0 {
SmallVecImpl::None => IntoIterImpl::None,
SmallVecImpl::One(i) => IntoIterImpl::One(i),
SmallVecImpl::Many(v) => IntoIterImpl::Many(v.into_iter()),
};
IntoIter(imp)
}
}