summaryrefslogtreecommitdiff
path: root/engine/src/stackvec.rs
diff options
context:
space:
mode:
authorMicha White <botahamec@outlook.com>2023-12-21 19:31:09 -0500
committerMicha White <botahamec@outlook.com>2023-12-21 19:31:09 -0500
commit655e896fb57ede428f889c6c7598f8954784e0dd (patch)
tree1b9bfbe379ad99acd285ef7997d1ebe4bb3f3f30 /engine/src/stackvec.rs
parent0185f2ef9159a868afa03c6e8d76f6d77f52f4f9 (diff)
Remove some memory allocations
Diffstat (limited to 'engine/src/stackvec.rs')
-rw-r--r--engine/src/stackvec.rs99
1 files changed, 99 insertions, 0 deletions
diff --git a/engine/src/stackvec.rs b/engine/src/stackvec.rs
new file mode 100644
index 0000000..9c00461
--- /dev/null
+++ b/engine/src/stackvec.rs
@@ -0,0 +1,99 @@
+use std::mem::MaybeUninit;
+use std::ops::{Deref, DerefMut};
+
+pub struct StackVec<T, const CAPACITY: usize> {
+ values: [MaybeUninit<T>; CAPACITY],
+ len: usize,
+}
+
+impl<T, const CAPACITY: usize> Deref for StackVec<T, CAPACITY> {
+ type Target = [T];
+
+ fn deref(&self) -> &Self::Target {
+ self.as_slice()
+ }
+}
+
+impl<T, const CAPACITY: usize> DerefMut for StackVec<T, CAPACITY> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.as_mut_slice()
+ }
+}
+
+impl<T, const CAPACITY: usize> FromIterator<T> for StackVec<T, CAPACITY> {
+ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
+ let mut this = Self::new();
+ for item in iter {
+ this.push(item);
+ }
+
+ this
+ }
+}
+
+impl<T, const CAPACITY: usize> StackVec<T, CAPACITY> {
+ pub fn new() -> Self {
+ Self {
+ values: MaybeUninit::uninit_array(),
+ len: 0,
+ }
+ }
+
+ pub fn capcity(&self) -> usize {
+ CAPACITY
+ }
+
+ pub fn len(&self) -> usize {
+ self.len
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.len == 0
+ }
+
+ pub fn as_slice(&self) -> &[T] {
+ // safety: the first `len` elements are guaranteed to be initialized
+ unsafe { MaybeUninit::slice_assume_init_ref(&self.values[..self.len]) }
+ }
+
+ pub fn as_mut_slice(&mut self) -> &mut [T] {
+ // safety: the first `len` elements are guaranteed to be initialized
+ unsafe { MaybeUninit::slice_assume_init_mut(&mut self.values[..self.len]) }
+ }
+
+ pub fn as_ptr(&self) -> *const T {
+ self.values.as_ptr().cast()
+ }
+
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self.values.as_mut_ptr().cast()
+ }
+
+ pub fn try_push(&mut self, value: T) -> Option<()> {
+ self.values.get_mut(self.len)?.write(value);
+ self.len += 1;
+ Some(())
+ }
+
+ pub fn push(&mut self, value: T) {
+ self.values[self.len].write(value);
+ self.len += 1;
+ }
+
+ pub fn pop(&mut self) -> Option<T> {
+ if self.is_empty() {
+ return None;
+ }
+
+ // safety: this value will no longer be used, and the value is valid
+ // because it appears in the valid part of the array
+ unsafe {
+ self.len -= 1;
+ Some(std::ptr::read(self.as_ptr().add(self.len())))
+ }
+ }
+
+ pub fn clear(&mut self) {
+ self.len = 0;
+ }
+}