2020-05-05 06:24:13 +02:00
|
|
|
//! Module containing various utility types and functions.
|
2020-05-16 18:24:07 +02:00
|
|
|
//!
|
|
|
|
//! # Safety
|
|
|
|
//!
|
|
|
|
//! The `StaticVec` type has some `unsafe` blocks.
|
2020-05-05 06:24:13 +02:00
|
|
|
|
2020-05-16 18:24:07 +02:00
|
|
|
use crate::r#unsafe::unsafe_uninit;
|
2020-05-14 12:27:22 +02:00
|
|
|
|
2020-05-05 06:24:13 +02:00
|
|
|
use crate::stdlib::{
|
|
|
|
any::TypeId,
|
2020-05-05 09:00:10 +02:00
|
|
|
fmt,
|
2020-05-05 06:24:13 +02:00
|
|
|
hash::{Hash, Hasher},
|
2020-05-10 15:25:47 +02:00
|
|
|
iter::FromIterator,
|
2020-05-05 06:24:13 +02:00
|
|
|
mem,
|
2020-05-16 18:24:07 +02:00
|
|
|
ops::Drop,
|
2020-05-05 06:24:13 +02:00
|
|
|
vec::Vec,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_std"))]
|
2020-05-10 15:25:47 +02:00
|
|
|
use crate::stdlib::collections::hash_map::DefaultHasher;
|
2020-05-05 06:24:13 +02:00
|
|
|
|
|
|
|
#[cfg(feature = "no_std")]
|
|
|
|
use ahash::AHasher;
|
|
|
|
|
2020-05-13 04:19:18 +02:00
|
|
|
#[inline(always)]
|
2020-05-08 05:34:56 +02:00
|
|
|
pub fn EMPTY_TYPE_ID() -> TypeId {
|
|
|
|
TypeId::of::<()>()
|
|
|
|
}
|
|
|
|
|
2020-05-07 18:19:08 +02:00
|
|
|
/// Calculate a `u64` hash key from a module-qualified function name and parameter types.
|
2020-05-05 06:24:13 +02:00
|
|
|
///
|
2020-05-07 18:19:08 +02:00
|
|
|
/// Module names are passed in via `&str` references from an iterator.
|
|
|
|
/// Parameter types are passed in via `TypeId` values from an iterator.
|
|
|
|
///
|
2020-05-10 15:25:47 +02:00
|
|
|
/// # Note
|
2020-05-07 18:19:08 +02:00
|
|
|
///
|
|
|
|
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
|
|
|
pub fn calc_fn_spec<'a>(
|
|
|
|
modules: impl Iterator<Item = &'a str>,
|
|
|
|
fn_name: &str,
|
|
|
|
params: impl Iterator<Item = TypeId>,
|
|
|
|
) -> u64 {
|
2020-05-05 06:24:13 +02:00
|
|
|
#[cfg(feature = "no_std")]
|
|
|
|
let mut s: AHasher = Default::default();
|
|
|
|
#[cfg(not(feature = "no_std"))]
|
|
|
|
let mut s = DefaultHasher::new();
|
|
|
|
|
2020-05-07 18:19:08 +02:00
|
|
|
// We always skip the first module
|
|
|
|
modules.skip(1).for_each(|m| m.hash(&mut s));
|
2020-05-05 06:24:13 +02:00
|
|
|
s.write(fn_name.as_bytes());
|
|
|
|
params.for_each(|t| t.hash(&mut s));
|
|
|
|
s.finish()
|
|
|
|
}
|
|
|
|
|
2020-05-16 18:24:07 +02:00
|
|
|
const MAX_STATIC_VEC: usize = 4;
|
|
|
|
|
2020-05-05 06:24:13 +02:00
|
|
|
/// A type to hold a number of values in static storage for speed, and any spill-overs in a `Vec`.
|
|
|
|
///
|
|
|
|
/// 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.
|
2020-05-10 15:25:47 +02:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2020-05-16 18:24:07 +02:00
|
|
|
/// This type uses some unsafe code (mainly for uninitialized/unused array slots) for efficiency.
|
2020-05-14 05:21:56 +02:00
|
|
|
//
|
|
|
|
// TODO - remove unsafe code
|
2020-05-10 15:25:47 +02:00
|
|
|
pub struct StaticVec<T> {
|
2020-05-05 06:24:13 +02:00
|
|
|
/// Total number of values held.
|
|
|
|
len: usize,
|
2020-05-16 18:24:07 +02:00
|
|
|
/// Static storage. 4 slots should be enough for most cases - i.e. four items of fast, no-allocation access.
|
|
|
|
list: [mem::MaybeUninit<T>; MAX_STATIC_VEC],
|
2020-05-05 06:24:13 +02:00
|
|
|
/// Dynamic storage. For spill-overs.
|
|
|
|
more: Vec<T>,
|
|
|
|
}
|
|
|
|
|
2020-05-16 18:24:07 +02:00
|
|
|
impl<T> Drop for StaticVec<T> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Default for StaticVec<T> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
len: 0,
|
|
|
|
list: unsafe_uninit(),
|
|
|
|
more: Vec::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 12:48:25 +02:00
|
|
|
impl<T: PartialEq> PartialEq for StaticVec<T> {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2020-05-16 18:24:07 +02:00
|
|
|
self.len == other.len
|
|
|
|
//&& self.list[0..self.len] == other.list[0..self.len]
|
|
|
|
&& self.more == other.more
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Clone> Clone for StaticVec<T> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
let mut value: Self = Default::default();
|
|
|
|
value.len = self.len;
|
|
|
|
|
|
|
|
if self.len <= self.list.len() {
|
|
|
|
for x in 0..self.len {
|
|
|
|
let item: &T = unsafe { mem::transmute(self.list.get(x).unwrap()) };
|
|
|
|
value.list[x] = mem::MaybeUninit::new(item.clone());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
value.more = self.more.clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
value
|
2020-05-12 12:48:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Eq> Eq for StaticVec<T> {}
|
|
|
|
|
2020-05-10 15:25:47 +02:00
|
|
|
impl<T> FromIterator<T> for StaticVec<T> {
|
2020-05-10 10:56:17 +02:00
|
|
|
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
|
|
|
|
let mut vec = StaticVec::new();
|
|
|
|
|
|
|
|
for x in iter {
|
|
|
|
vec.push(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
vec
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-10 15:25:47 +02:00
|
|
|
impl<T> StaticVec<T> {
|
2020-05-16 18:24:07 +02:00
|
|
|
fn extract(value: mem::MaybeUninit<T>) -> T {
|
|
|
|
unsafe { value.assume_init() }
|
|
|
|
}
|
2020-05-05 06:24:13 +02:00
|
|
|
/// Create a new `StaticVec`.
|
|
|
|
pub fn new() -> Self {
|
2020-05-05 09:00:10 +02:00
|
|
|
Default::default()
|
2020-05-05 06:24:13 +02:00
|
|
|
}
|
2020-05-16 18:24:07 +02:00
|
|
|
/// Empty the `StaticVec`.
|
|
|
|
pub fn clear(&mut self) {
|
|
|
|
if self.len <= self.list.len() {
|
|
|
|
for x in 0..self.len {
|
|
|
|
Self::extract(mem::replace(
|
|
|
|
self.list.get_mut(x).unwrap(),
|
|
|
|
mem::MaybeUninit::uninit(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.more.clear();
|
|
|
|
}
|
|
|
|
self.len = 0;
|
|
|
|
}
|
2020-05-05 06:24:13 +02:00
|
|
|
/// Push a new value to the end of this `StaticVec`.
|
|
|
|
pub fn push<X: Into<T>>(&mut self, value: X) {
|
2020-05-10 15:25:47 +02:00
|
|
|
if self.len == self.list.len() {
|
|
|
|
// Move the fixed list to the Vec
|
2020-05-16 18:24:07 +02:00
|
|
|
self.more.extend(
|
|
|
|
self.list
|
|
|
|
.iter_mut()
|
|
|
|
.map(|v| mem::replace(v, mem::MaybeUninit::uninit()))
|
|
|
|
.map(Self::extract),
|
|
|
|
);
|
2020-05-10 15:25:47 +02:00
|
|
|
self.more.push(value.into());
|
2020-05-16 18:24:07 +02:00
|
|
|
} else if self.len < self.list.len() {
|
|
|
|
mem::replace(
|
|
|
|
self.list.get_mut(self.len).unwrap(),
|
|
|
|
mem::MaybeUninit::new(value.into()),
|
|
|
|
);
|
|
|
|
} else {
|
2020-05-05 06:24:13 +02:00
|
|
|
self.more.push(value.into());
|
2020-05-16 18:24:07 +02:00
|
|
|
}
|
|
|
|
self.len += 1;
|
|
|
|
}
|
|
|
|
/// Insert a new value to this `StaticVec` at a particular position.
|
|
|
|
pub fn insert<X: Into<T>>(&mut self, index: usize, value: X) {
|
|
|
|
if index > self.len {
|
|
|
|
panic!("index OOB in StaticVec");
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.len == self.list.len() {
|
|
|
|
// Move the fixed list to the Vec
|
|
|
|
self.more.extend(
|
|
|
|
self.list
|
|
|
|
.iter_mut()
|
|
|
|
.map(|v| mem::replace(v, mem::MaybeUninit::uninit()))
|
|
|
|
.map(Self::extract),
|
|
|
|
);
|
|
|
|
self.more.insert(index, value.into());
|
|
|
|
} else if self.len < self.list.len() {
|
|
|
|
for x in (index..self.len).rev() {
|
|
|
|
let temp = mem::replace(self.list.get_mut(x).unwrap(), mem::MaybeUninit::uninit());
|
|
|
|
mem::replace(self.list.get_mut(x + 1).unwrap(), temp);
|
|
|
|
}
|
|
|
|
mem::replace(
|
|
|
|
self.list.get_mut(index).unwrap(),
|
|
|
|
mem::MaybeUninit::new(value.into()),
|
|
|
|
);
|
2020-05-05 06:24:13 +02:00
|
|
|
} else {
|
2020-05-16 18:24:07 +02:00
|
|
|
self.more.insert(index, value.into());
|
2020-05-05 06:24:13 +02:00
|
|
|
}
|
|
|
|
self.len += 1;
|
|
|
|
}
|
|
|
|
/// Pop a value from the end of this `StaticVec`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the `StaticVec` is empty.
|
|
|
|
pub fn pop(&mut self) -> T {
|
2020-05-16 18:24:07 +02:00
|
|
|
if self.len <= 0 {
|
|
|
|
panic!("nothing to pop!");
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = if self.len <= self.list.len() {
|
|
|
|
Self::extract(mem::replace(
|
|
|
|
self.list.get_mut(self.len - 1).unwrap(),
|
|
|
|
mem::MaybeUninit::uninit(),
|
|
|
|
))
|
2020-05-05 06:24:13 +02:00
|
|
|
} else {
|
2020-05-10 15:25:47 +02:00
|
|
|
let r = self.more.pop().unwrap();
|
|
|
|
|
|
|
|
// Move back to the fixed list
|
|
|
|
if self.more.len() == self.list.len() {
|
2020-05-16 18:24:07 +02:00
|
|
|
for index in (0..self.list.len()).rev() {
|
|
|
|
mem::replace(
|
|
|
|
self.list.get_mut(index).unwrap(),
|
|
|
|
mem::MaybeUninit::new(self.more.pop().unwrap()),
|
|
|
|
);
|
2020-05-10 15:25:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r
|
2020-05-05 06:24:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
self.len -= 1;
|
|
|
|
|
|
|
|
result
|
|
|
|
}
|
|
|
|
/// Get the number of items in this `StaticVec`.
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.len
|
|
|
|
}
|
2020-05-16 18:24:07 +02:00
|
|
|
/// Is this `StaticVec` empty?
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.len == 0
|
|
|
|
}
|
2020-05-10 15:25:47 +02:00
|
|
|
/// Get a reference to the item at a particular index.
|
2020-05-05 06:24:13 +02:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the index is out of bounds.
|
2020-05-10 15:25:47 +02:00
|
|
|
pub fn get_ref(&self, index: usize) -> &T {
|
2020-05-05 06:24:13 +02:00
|
|
|
if index >= self.len {
|
|
|
|
panic!("index OOB in StaticVec");
|
|
|
|
}
|
|
|
|
|
2020-05-16 18:24:07 +02:00
|
|
|
let list: &[T; MAX_STATIC_VEC] = unsafe { mem::transmute(&self.list) };
|
|
|
|
|
|
|
|
if self.len <= list.len() {
|
|
|
|
list.get(index).unwrap()
|
2020-05-05 06:24:13 +02:00
|
|
|
} else {
|
2020-05-10 15:25:47 +02:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2020-05-16 18:24:07 +02:00
|
|
|
let list: &mut [T; MAX_STATIC_VEC] = unsafe { mem::transmute(&mut self.list) };
|
|
|
|
|
|
|
|
if self.len <= list.len() {
|
|
|
|
list.get_mut(index).unwrap()
|
2020-05-10 15:25:47 +02:00
|
|
|
} else {
|
|
|
|
self.more.get_mut(index).unwrap()
|
2020-05-05 06:24:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Get an iterator to entries in the `StaticVec`.
|
|
|
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
2020-05-16 18:24:07 +02:00
|
|
|
let list: &[T; MAX_STATIC_VEC] = unsafe { mem::transmute(&self.list) };
|
|
|
|
|
|
|
|
if self.len <= list.len() {
|
|
|
|
list[..self.len].iter()
|
2020-05-05 06:24:13 +02:00
|
|
|
} else {
|
2020-05-16 18:24:07 +02:00
|
|
|
self.more.iter()
|
2020-05-10 15:25:47 +02:00
|
|
|
}
|
2020-05-05 06:24:13 +02:00
|
|
|
}
|
2020-05-07 04:00:10 +02:00
|
|
|
/// Get a mutable iterator to entries in the `StaticVec`.
|
|
|
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
2020-05-16 18:24:07 +02:00
|
|
|
let list: &mut [T; MAX_STATIC_VEC] = unsafe { mem::transmute(&mut self.list) };
|
|
|
|
|
|
|
|
if self.len <= list.len() {
|
|
|
|
list[..self.len].iter_mut()
|
2020-05-07 04:00:10 +02:00
|
|
|
} else {
|
2020-05-16 18:24:07 +02:00
|
|
|
self.more.iter_mut()
|
2020-05-10 15:25:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-16 18:24:07 +02:00
|
|
|
impl<T: Default> StaticVec<T> {
|
|
|
|
/// Get the item at a particular index, replacing it with the default.
|
2020-05-10 15:25:47 +02:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the index is out of bounds.
|
2020-05-16 18:24:07 +02:00
|
|
|
pub fn get(&mut self, index: usize) -> T {
|
2020-05-10 15:25:47 +02:00
|
|
|
if index >= self.len {
|
|
|
|
panic!("index OOB in StaticVec");
|
|
|
|
}
|
2020-05-07 04:00:10 +02:00
|
|
|
|
2020-05-16 18:24:07 +02:00
|
|
|
mem::take(if self.len <= self.list.len() {
|
|
|
|
unsafe { mem::transmute(self.list.get_mut(index).unwrap()) }
|
2020-05-10 15:25:47 +02:00
|
|
|
} else {
|
2020-05-16 18:24:07 +02:00
|
|
|
self.more.get_mut(index).unwrap()
|
|
|
|
})
|
2020-05-07 04:00:10 +02:00
|
|
|
}
|
2020-05-05 06:24:13 +02:00
|
|
|
}
|
2020-05-05 09:00:10 +02:00
|
|
|
|
2020-05-10 15:25:47 +02:00
|
|
|
impl<T: fmt::Debug> fmt::Debug for StaticVec<T> {
|
2020-05-05 09:00:10 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(f, "[ ")?;
|
|
|
|
self.iter().try_for_each(|v| write!(f, "{:?}, ", v))?;
|
|
|
|
write!(f, "]")
|
|
|
|
}
|
|
|
|
}
|
2020-05-10 15:25:47 +02:00
|
|
|
|
|
|
|
impl<T> AsRef<[T]> for StaticVec<T> {
|
|
|
|
fn as_ref(&self) -> &[T] {
|
2020-05-16 18:24:07 +02:00
|
|
|
let list: &[T; MAX_STATIC_VEC] = unsafe { mem::transmute(&self.list) };
|
|
|
|
|
|
|
|
if self.len <= list.len() {
|
|
|
|
&list[..self.len]
|
2020-05-10 15:25:47 +02:00
|
|
|
} else {
|
2020-05-16 18:24:07 +02:00
|
|
|
&self.more[..]
|
2020-05-10 15:25:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> AsMut<[T]> for StaticVec<T> {
|
|
|
|
fn as_mut(&mut self) -> &mut [T] {
|
2020-05-16 18:24:07 +02:00
|
|
|
let list: &mut [T; MAX_STATIC_VEC] = unsafe { mem::transmute(&mut self.list) };
|
|
|
|
|
|
|
|
if self.len <= list.len() {
|
|
|
|
&mut list[..self.len]
|
|
|
|
} else {
|
2020-05-10 15:25:47 +02:00
|
|
|
&mut self.more[..]
|
2020-05-16 18:24:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> From<StaticVec<T>> for Vec<T> {
|
|
|
|
fn from(mut value: StaticVec<T>) -> Self {
|
|
|
|
if value.len <= value.list.len() {
|
|
|
|
value
|
|
|
|
.list
|
|
|
|
.iter_mut()
|
|
|
|
.map(|v| mem::replace(v, mem::MaybeUninit::uninit()))
|
|
|
|
.map(StaticVec::extract)
|
|
|
|
.collect()
|
2020-05-10 15:25:47 +02:00
|
|
|
} else {
|
2020-05-16 18:24:07 +02:00
|
|
|
let mut arr = Self::new();
|
|
|
|
arr.append(&mut value.more);
|
|
|
|
arr
|
2020-05-10 15:25:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-16 18:24:07 +02:00
|
|
|
|
|
|
|
impl<T> From<Vec<T>> for StaticVec<T> {
|
|
|
|
fn from(mut value: Vec<T>) -> Self {
|
|
|
|
let mut arr: Self = Default::default();
|
|
|
|
arr.len = value.len();
|
|
|
|
|
|
|
|
if arr.len <= arr.list.len() {
|
|
|
|
for x in (0..arr.len).rev() {
|
|
|
|
mem::replace(
|
|
|
|
arr.list.get_mut(x).unwrap(),
|
|
|
|
mem::MaybeUninit::new(value.pop().unwrap()),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
arr.more = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
arr
|
|
|
|
}
|
|
|
|
}
|