// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.
#![allow(unsafe_code)]
use core::slice; use std::{
fmt::Debug,
mem::MaybeUninit,
ops::{Deref, DerefMut},
};
/// Note: this implementation of SmallVec is not panic-safe, in the sense /// that in presence of panics the SmallVec will be left in some valid but /// unspecified state. pubenum SmallVec<T, const N: usize> {
Stack { // Safety invariant: the first `len` values of `data` are initialized.
len: usize,
data: [MaybeUninit<T>; N],
},
Heap(Vec<T>),
}
impl<T, const N: usize> Deref for SmallVec<T, N> { type Target = [T];
fn deref(&self) -> &[T] { matchself {
SmallVec::Stack { len, data } => { let data = &data[..*len]; // SAFETY: the safety invariant on `self` guarantees that the elements are // initialized, and T and MaybeUninit<T> have the same size and alignment. unsafe { slice::from_raw_parts(data.as_ptr().cast::<T>(), data.len()) }
}
SmallVec::Heap(v) => &v[..],
}
}
}
impl<T, const N: usize> DerefMut for SmallVec<T, N> { fn deref_mut(&mutself) -> &mut [T] { matchself {
SmallVec::Stack { len, data } => { let data = &mut data[..*len]; // SAFETY: the safety invariant on `self` guarantees that the elements are // initialized, and T and MaybeUninit<T> have the same size and alignment. unsafe { slice::from_raw_parts_mut(data.as_mut_ptr().cast::<T>(), data.len()) }
}
SmallVec::Heap(v) => &mut v[..],
}
}
}
#[inline(never)] fn move_to_heap(&mutself) { letSelf::Stack { len, data } = selfelse { // Nothing to do. return;
}; letmut ret = Vec::<T>::with_capacity(*len); let old_len = *len;
*len = 0; for data in data[..old_len].iter_mut() { letmut tmp = MaybeUninit::uninit();
std::mem::swap(&mut tmp, data); // SAFETY: the safety invariant on `self` promises that `data[i]` is initialized // for all i < old_len. Since we set `len` to 0, we are not breaking the safety // invariant if this function were to panic.
ret.push(unsafe { tmp.assume_init() });
}
*self = Self::Heap(ret);
}
// Note: if `iter` has an incorrect implementation of `size_hint` (specifically, incorrect // upper bound), some elements of `iter` may be discarded. #[inline(always)] pubfn extend<I: IntoIterator<Item = T>>(&mutself, iter: I) { letmut iter = iter.into_iter(); let new_size = iter.size_hint().1.and_then(|x| x.checked_add(self.len())); if new_size.is_none_or(|u| u > N) { self.move_to_heap();
} let (len, data) = matchself { Self::Heap(v) => {
v.extend(iter); return;
} Self::Stack { len, data } => (len, data),
};
// We now know `iter`'s elements fit on the stack. while *len < N
&& let Some(e) = iter.next()
{
data[*len].write(e); // Safety note: we just wrote a new element in the first non-initialized slot of // the array.
*len += 1;
}
}
#[inline] pubfn push(&mutself, val: T) { ifself.len() + 1 > N { self.move_to_heap();
} let (len, data) = matchself { Self::Heap(v) => {
v.push(val); return;
} Self::Stack { len, data } => (len, data),
};
data[*len].write(val); // Safety note: we just wrote a new element in the first non-initialized slot of // the array.
*len += 1;
}
// It is easier to implement this method than to implement IntoIterator. #[inline] pubfn extend_sv<const M: usize>(&mutself, mut other: SmallVec<T, M>) { ifself.len() + other.len() > N { self.move_to_heap();
} if matches!(self, Self::Heap(_)) {
other.move_to_heap();
} if matches!(other, SmallVec::Heap(_)) { self.move_to_heap();
} let (len, data) = matchself { Self::Heap(v) => { let SmallVec::Heap(o) = &mut other else {
unreachable!()
};
v.extend(std::mem::take(o)); return;
} Self::Stack { len, data } => (len, data),
};
// We now know `other`'s elements fit on the stack. let SmallVec::Stack {
len: olen,
data: odata,
} = &mut other else {
unreachable!()
}; let other_len = *olen;
*olen = 0;
data[*len..*len + other_len].swap_with_slice(&mut odata[..other_len]); // Safety note: we just wrote `other_len` elements in the first non-initialized slots // of the array.
*len += other_len;
}
}
impl<T, const N: usize> FromIterator<T> for SmallVec<T, N> { #[inline] fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { letmut ret = Self::new();
ret.extend(iter);
ret
}
}
impl<T, const N: usize> Drop for SmallVec<T, N> { fn drop(&mutself) { iflet SmallVec::Stack { len, data } = self { let old_len = *len;
*len = 0; for el in data[..old_len].iter_mut() { // SAFETY: by safety invariant, the first `old_len` elements are initialized. // We set *len to 0 to make sure we preserve the safety invariant, although // that should not be strictly necessary as *self cannot be accessed outside // this function anymore. unsafe { el.assume_init_drop() };
}
}
}
}
#[cfg(test)] mod tests { usesuper::*; use arbtest::arbitrary::Arbitrary;
let num_ops = u8::arbitrary(u)?; for _ in0..num_ops { let op_type = *u.choose(&[0, 1])?; if op_type == 0 { let val = u8::arbitrary(u)?;
smallvec.push(val);
vec.push(val);
} else { let num_elements = u8::arbitrary(u)? as usize; letmut elements = Vec::new(); for _ in0..num_elements {
elements.push(u8::arbitrary(u)?);
}
smallvec.extend(elements.iter().copied());
vec.extend(elements.iter().copied());
}
assert_eq!(&*smallvec, &*vec);
}
Ok(())
});
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.