chiark / gitweb /
AutoStackVec
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 17 Aug 2022 14:25:55 +0000 (15:25 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 17 Aug 2022 14:25:55 +0000 (15:25 +0100)
src/main.rs

index 476e59ccc16ac259ac8bebca9fe91668d2b00456..f82867b3533d484660a6e05ea909969e114c8a13 100644 (file)
 #![allow(unused_variables)]
 #![allow(unused_imports)]
 
+use std::fmt::{self, Debug};
+use std::marker::PhantomData;
 use std::mem;
 use std::mem::MaybeUninit;
+use std::ops::Deref;
 
 pub fn default<T: Default>() -> T { Default::default() }
 
-#[derive(Debug)]
-struct AutoStackVec<const N: usize, T> {
+pub struct AutoStackVec<T, B> {
     used: usize,
-    buf: [T; N],
+    ph: PhantomData<T>,
+    buf: B,
 }
 
-impl<const N: usize, T> AutoStackVec<N,T> {
-    fn new() -> Self where T: Default {
+impl<T,B> Deref for AutoStackVec<T, B> where B: Buffer<T> {
+    type Target = [T];
+    fn deref(&self) -> &[T] {
+        unsafe {
+            std::slice::from_raw_parts(
+                self.buf.raw_ptr() as _,
+                self.used,
+            )
+        }
+    }
+}
+
+impl<T,B> Debug for AutoStackVec<T, B> where B: Buffer<T>, T: Debug {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        <[T] as Debug>::fmt(&*self, f)
+    }
+}
+
+#[repr(C)]
+pub struct Buf1<T, B> {
+    earlier: B,
+    item: MaybeUninit<T>,
+}
+
+pub unsafe trait Buffer<T> {
+    fn len() -> usize;
+    fn raw_ptr(&self) -> *const MaybeUninit<T> { self as *const _ as _ }
+    fn raw_mut(&mut self) -> *mut MaybeUninit<T> { self as *mut _ as _ }
+}
+unsafe impl<T> Buffer<T> for () {
+    fn len() -> usize { 0 }
+}
+unsafe impl<T,B> Buffer<T> for Buf1<T, B> where B: Buffer<T> {
+    fn len() -> usize { B::len() + 1 }
+}
+
+impl<T> AutoStackVec<T, ()> {
+    pub fn new() -> Self {
         AutoStackVec {
             used: 0,
-            buf: std::array::from_fn(|_| default()),
+            ph: PhantomData,
+            buf: (),
+        }
+    }
+}
+
+impl<T,B> AutoStackVec<T, B> where B: Buffer<T> {
+    pub fn push_none(mut self) -> AutoStackVec<T, Buf1<T, B>> {
+        let mut out = AutoStackVec {
+            used: 0,
+            ph: self.ph,
+            buf: Buf1 {
+                earlier: self.buf,
+                item: MaybeUninit::uninit(),
+            },
+        };
+        out.used = self.used;
+        self.used = 0;
+        out
+    }
+
+    pub fn push(self, item: T) -> AutoStackVec<T, Buf1<T, B>> {
+        unsafe {
+            let mut out = self.push_none();
+            let item = MaybeUninit::new(item);
+            (out.buf.raw_mut())
+                .add(out.used)
+                .write(item);
+            out.used += 1;
+            out
+        }
+    }
+
+    pub fn push_option(self, item: Option<T>) -> AutoStackVec<T, Buf1<T, B>> {
+        if let Some(item) = item {
+            self.push(item)
+        } else {
+            self.push_none()
         }
     }
 }
 
 fn main(){
-    let asv = AutoStackVec::<4, i32>::new();
+    let asv = AutoStackVec::<i32,_>::new();
+    let asv = asv.push(42);
     eprintln!("N {:?}", asv);
 }