Use StaticVec to avoid most allocations with function arguments.
This commit is contained in:
138
src/utils.rs
138
src/utils.rs
@@ -1,15 +1,18 @@
|
||||
//! Module containing various utility types and functions.
|
||||
//
|
||||
// TODO - remove unsafe code
|
||||
|
||||
use crate::stdlib::{
|
||||
any::TypeId,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
iter::FromIterator,
|
||||
mem,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
use crate::stdlib::{collections::hash_map::DefaultHasher, iter::FromIterator};
|
||||
use crate::stdlib::collections::hash_map::DefaultHasher;
|
||||
|
||||
#[cfg(feature = "no_std")]
|
||||
use ahash::AHasher;
|
||||
@@ -23,7 +26,7 @@ pub fn EMPTY_TYPE_ID() -> TypeId {
|
||||
/// Module names are passed in via `&str` references from an iterator.
|
||||
/// Parameter types are passed in via `TypeId` values from an iterator.
|
||||
///
|
||||
/// ### Note
|
||||
/// # Note
|
||||
///
|
||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||
pub fn calc_fn_spec<'a>(
|
||||
@@ -47,8 +50,12 @@ pub fn calc_fn_spec<'a>(
|
||||
///
|
||||
/// This is essentially a knock-off of the [`staticvec`](https://crates.io/crates/staticvec) crate.
|
||||
/// This simplified implementation here is to avoid pulling in another crate.
|
||||
#[derive(Clone, Hash, Default)]
|
||||
pub struct StaticVec<T: Default> {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This type uses some unsafe code (mainly to zero out unused array slots) for efficiency.
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct StaticVec<T> {
|
||||
/// Total number of values held.
|
||||
len: usize,
|
||||
/// Static storage. 4 slots should be enough for most cases - i.e. four levels of indirection.
|
||||
@@ -57,7 +64,17 @@ pub struct StaticVec<T: Default> {
|
||||
more: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: Default> FromIterator<T> for StaticVec<T> {
|
||||
impl<T> Default for StaticVec<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
len: 0,
|
||||
list: unsafe { mem::MaybeUninit::zeroed().assume_init() },
|
||||
more: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromIterator<T> for StaticVec<T> {
|
||||
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
|
||||
let mut vec = StaticVec::new();
|
||||
|
||||
@@ -69,14 +86,22 @@ impl<T: Default> FromIterator<T> for StaticVec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> StaticVec<T> {
|
||||
impl<T> StaticVec<T> {
|
||||
/// Create a new `StaticVec`.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
/// Push a new value to the end of this `StaticVec`.
|
||||
pub fn push<X: Into<T>>(&mut self, value: X) {
|
||||
if self.len >= self.list.len() {
|
||||
if self.len == self.list.len() {
|
||||
// Move the fixed list to the Vec
|
||||
for x in 0..self.list.len() {
|
||||
let def_val: T = unsafe { mem::MaybeUninit::zeroed().assume_init() };
|
||||
self.more
|
||||
.push(mem::replace(self.list.get_mut(x).unwrap(), def_val));
|
||||
}
|
||||
self.more.push(value.into());
|
||||
} else if self.len > self.list.len() {
|
||||
self.more.push(value.into());
|
||||
} else {
|
||||
self.list[self.len] = value.into();
|
||||
@@ -92,9 +117,19 @@ impl<T: Default> StaticVec<T> {
|
||||
let result = if self.len <= 0 {
|
||||
panic!("nothing to pop!")
|
||||
} else if self.len <= self.list.len() {
|
||||
mem::take(self.list.get_mut(self.len - 1).unwrap())
|
||||
let def_val: T = unsafe { mem::MaybeUninit::zeroed().assume_init() };
|
||||
mem::replace(self.list.get_mut(self.len - 1).unwrap(), def_val)
|
||||
} else {
|
||||
self.more.pop().unwrap()
|
||||
let r = self.more.pop().unwrap();
|
||||
|
||||
// Move back to the fixed list
|
||||
if self.more.len() == self.list.len() {
|
||||
for x in 0..self.list.len() {
|
||||
self.list[self.list.len() - 1 - x] = self.more.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
r
|
||||
};
|
||||
|
||||
self.len -= 1;
|
||||
@@ -105,48 +140,99 @@ impl<T: Default> StaticVec<T> {
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
/// Get an item at a particular index.
|
||||
/// Get a reference to the item at a particular index.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
pub fn get(&self, index: usize) -> &T {
|
||||
pub fn get_ref(&self, index: usize) -> &T {
|
||||
if index >= self.len {
|
||||
panic!("index OOB in StaticVec");
|
||||
}
|
||||
|
||||
if index < self.list.len() {
|
||||
if self.len < self.list.len() {
|
||||
self.list.get(index).unwrap()
|
||||
} else {
|
||||
self.more.get(index - self.list.len()).unwrap()
|
||||
self.more.get(index).unwrap()
|
||||
}
|
||||
}
|
||||
/// Get a mutable reference to the item at a particular index.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
pub fn get_mut(&mut self, index: usize) -> &mut T {
|
||||
if index >= self.len {
|
||||
panic!("index OOB in StaticVec");
|
||||
}
|
||||
|
||||
if self.len < self.list.len() {
|
||||
self.list.get_mut(index).unwrap()
|
||||
} else {
|
||||
self.more.get_mut(index).unwrap()
|
||||
}
|
||||
}
|
||||
/// Get an iterator to entries in the `StaticVec`.
|
||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
let num = if self.len >= self.list.len() {
|
||||
self.list.len()
|
||||
if self.len > self.list.len() {
|
||||
self.more.iter()
|
||||
} else {
|
||||
self.len
|
||||
};
|
||||
|
||||
self.list[..num].iter().chain(self.more.iter())
|
||||
self.list[..self.len].iter()
|
||||
}
|
||||
}
|
||||
/// Get a mutable iterator to entries in the `StaticVec`.
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||
let num = if self.len >= self.list.len() {
|
||||
self.list.len()
|
||||
if self.len > self.list.len() {
|
||||
self.more.iter_mut()
|
||||
} else {
|
||||
self.len
|
||||
};
|
||||
|
||||
self.list[..num].iter_mut().chain(self.more.iter_mut())
|
||||
self.list[..self.len].iter_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Clone + fmt::Debug> fmt::Debug for StaticVec<T> {
|
||||
impl<T: Copy> StaticVec<T> {
|
||||
/// Get the item at a particular index.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
pub fn get(&self, index: usize) -> T {
|
||||
if index >= self.len {
|
||||
panic!("index OOB in StaticVec");
|
||||
}
|
||||
|
||||
if self.len < self.list.len() {
|
||||
*self.list.get(index).unwrap()
|
||||
} else {
|
||||
*self.more.get(index).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for StaticVec<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "[ ")?;
|
||||
self.iter().try_for_each(|v| write!(f, "{:?}, ", v))?;
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<[T]> for StaticVec<T> {
|
||||
fn as_ref(&self) -> &[T] {
|
||||
if self.len > self.list.len() {
|
||||
&self.more[..]
|
||||
} else {
|
||||
&self.list[..self.len]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<[T]> for StaticVec<T> {
|
||||
fn as_mut(&mut self) -> &mut [T] {
|
||||
if self.len > self.list.len() {
|
||||
&mut self.more[..]
|
||||
} else {
|
||||
&mut self.list[..self.len]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user