Changeset - 2c42c44db744
[Not reviewed]
0 3 0
Christopher Esterhuyse - 5 years ago 2020-02-20 14:22:27
christopher.esterhuyse@gmail.com
vec storage for port backings
3 files changed with 222 insertions and 27 deletions:
0 comments (0 inline, 0 general)
src/lib.rs
Show inline comments
 
@@ -10,7 +10,5 @@ mod test;
 

	
 
pub use runtime::{errors, Connector, PortBinding};
 

	
 
pub use crate::runtime::experimental::api::Port;
 

	
 
#[cfg(feature = "ffi")]
 
pub use runtime::ffi;
src/runtime/experimental/api.rs
Show inline comments
 
@@ -2,6 +2,8 @@ use crate::common::*;
 
use crate::runtime::endpoint::Endpoint;
 
use crate::runtime::endpoint::EndpointExt;
 
use crate::runtime::endpoint::EndpointInfo;
 
use core::mem::MaybeUninit;
 
use std::collections::BTreeSet;
 

	
 
use std::net::SocketAddr;
 
use std::sync::Arc;
 
@@ -25,30 +27,6 @@ impl From<(Coupling, Polarity, SocketAddr)> for Binding {
 
    }
 
}
 

	
 
pub struct MsgBuffer<'a> {
 
    slice: &'a mut [u8],
 
    len: usize,
 
}
 
impl MsgBuffer<'_> {
 
    pub fn clear(&mut self) {
 
        self.len = 0;
 
    }
 
    pub fn write_msg(&mut self, r: &[u8]) -> std::io::Result<()> {
 
        use std::io::Write;
 
        self.slice.write_all(r)?;
 
        self.len = r.len();
 
        Ok(())
 
    }
 
    pub fn read_msg(&self) -> &[u8] {
 
        &self.slice[0..self.len]
 
    }
 
}
 
impl<'a> From<&'a mut [u8]> for MsgBuffer<'a> {
 
    fn from(slice: &'a mut [u8]) -> Self {
 
        Self { slice, len: 0 }
 
    }
 
}
 

	
 
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 
#[repr(C)]
 
pub struct Port(pub u32);
 
@@ -296,3 +274,222 @@ unsafe fn as_mut_slice<'a, T>(len: usize, ptr: *mut T) -> &'a mut [T] {
 
unsafe fn as_const_slice<'a, T>(len: usize, ptr: *const T) -> &'a [T] {
 
    std::slice::from_raw_parts(ptr, len)
 
}
 

	
 
// data contains values in one of three states:
 
// 1. occupied: ininitialized. will be dropped.
 
// 2. vacant: uninitialized. may be reused implicitly. won't be dropped.
 
// 2. reserved: uninitialized. may be occupied implicitly. won't be dropped.
 
struct VecStorage<T> {
 
    // invariant A: elements at indices (0..data.len()) / vacant / reserved are occupied
 
    // invariant B: reserved & vacant = {}
 
    // invariant C: (vacant U reserved) subset of (0..data.len)
 
    data: Vec<MaybeUninit<T>>,
 
    vacant: BTreeSet<usize>,
 
    reserved: BTreeSet<usize>,
 
}
 
impl<T> Default for VecStorage<T> {
 
    fn default() -> Self {
 
        Self { data: Default::default(), vacant: Default::default(), reserved: Default::default() }
 
    }
 
}
 
impl<T> Debug for VecStorage<T>
 
where
 
    T: Debug,
 
{
 
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
 
        enum FmtT<'a, T> {
 
            Vacant,
 
            Reserved,
 
            Occupied(&'a T),
 
        };
 
        impl<T> Debug for FmtT<'_, T>
 
        where
 
            T: Debug,
 
        {
 
            fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
 
                match self {
 
                    FmtT::Vacant => write!(f, "Vacant"),
 
                    FmtT::Reserved => write!(f, "Reserved"),
 
                    FmtT::Occupied(t) => write!(f, "Occupied({:?})", t),
 
                }
 
            }
 
        }
 
        let iter = (0..self.data.len()).map(|i| {
 
            if self.vacant.contains(&i) {
 
                FmtT::Vacant
 
            } else if self.reserved.contains(&i) {
 
                FmtT::Reserved
 
            } else {
 
                // 2. Invariant A => reading valid ata
 
                unsafe {
 
                    // 1. index is within bounds
 
                    // 2. i is occupied => initialized data is being dropped
 
                    FmtT::Occupied(&*self.data.get_unchecked(i).as_ptr())
 
                }
 
            }
 
        });
 
        f.debug_list().entries(iter).finish()
 
    }
 
}
 
impl<T> Drop for VecStorage<T> {
 
    fn drop(&mut self) {
 
        self.clear();
 
    }
 
}
 
impl<T> VecStorage<T> {
 
    // ASSUMES that i in 0..self.data.len()
 
    unsafe fn get_occupied_unchecked(&self, i: usize) -> Option<&T> {
 
        if self.vacant.contains(&i) || self.reserved.contains(&i) {
 
            None
 
        } else {
 
            // 2. Invariant A => reading valid ata
 
            Some(&*self.data.get_unchecked(i).as_ptr())
 
        }
 
    }
 
    // ASSUMES that i in 0..self.data.len()
 
    unsafe fn get_mut_occupied_unchecked(&mut self, i: usize) -> Option<&mut T> {
 
        if self.vacant.contains(&i) || self.reserved.contains(&i) {
 
            None
 
        } else {
 
            // 2. Invariant A => reading valid ata
 
            Some(&mut *self.data.get_unchecked_mut(i).as_mut_ptr())
 
        }
 
    }
 
    // breaks invariant A: returned index is in NO state
 
    fn pop_vacant(&mut self) -> usize {
 
        if let Some(i) = pop_set_arb(&mut self.vacant) {
 
            i
 
        } else {
 
            self.data.push(MaybeUninit::uninit());
 
            self.data.len() - 1
 
        }
 
    }
 
    //////////////
 
    pub fn clear(&mut self) {
 
        for i in 0..self.data.len() {
 
            if !self.vacant.contains(&i) && !self.reserved.contains(&i) {
 
                // invariant A: this element is OCCUPIED
 
                unsafe {
 
                    // 1. by construction, i is in bounds
 
                    // 2. i is occupied => initialized data is being dropped
 
                    drop(self.data.get_unchecked_mut(i).as_ptr().read());
 
                }
 
            }
 
        }
 
        self.vacant.clear();
 
        self.reserved.clear();
 
    }
 
    pub fn iter(&self) -> impl Iterator<Item = &T> {
 
        (0..self.data.len()).filter_map(move |i| unsafe { self.get_occupied_unchecked(i) })
 
    }
 
    pub fn get_occupied(&self, i: usize) -> Option<&T> {
 
        if i >= self.data.len() {
 
            None
 
        } else {
 
            unsafe {
 
                // index is within bounds
 
                self.get_occupied_unchecked(i)
 
            }
 
        }
 
    }
 
    pub fn get_mut_occupied(&mut self, i: usize) -> Option<&mut T> {
 
        if i >= self.data.len() {
 
            None
 
        } else {
 
            unsafe {
 
                // index is within bounds
 
                self.get_mut_occupied_unchecked(i)
 
            }
 
        }
 
    }
 
    pub fn new_reserved(&mut self) -> usize {
 
        let i = self.pop_vacant(); // breaks invariant A: i is in NO state
 
        self.reserved.insert(i); // restores invariant A
 
        i
 
    }
 
    pub fn occupy_reserved(&mut self, i: usize, t: T) {
 
        assert!(self.reserved.remove(&i)); // breaks invariant A
 
        unsafe {
 
            // 1. invariant C => write is within bounds
 
            // 2. i WAS reserved => no initialized data is being overwritten
 
            self.data.get_unchecked_mut(i).as_mut_ptr().write(t)
 
            // restores invariant A
 
        };
 
    }
 
    pub fn new_occupied(&mut self, t: T) -> usize {
 
        let i = self.pop_vacant(); // breaks invariant A: i is in NO state
 
        unsafe {
 
            // 1. invariant C => write is within bounds
 
            // 2. i WAS reserved => no initialized data is being overwritten
 
            self.data.get_unchecked_mut(i).as_mut_ptr().write(t)
 
            // restores invariant A
 
        };
 
        i
 
    }
 
    pub fn vacate(&mut self, i: usize) -> Option<T> {
 
        if i >= self.data.len() || self.vacant.contains(&i) {
 
            // already vacant. nothing to do here
 
            return None;
 
        }
 
        // i is certainly within bounds of self.data
 
        let value = if self.reserved.remove(&i) {
 
            // no data to drop
 
            None
 
        } else {
 
            // invariant A => this element is OCCUPIED!
 
            unsafe {
 
                // 1. index is within bounds
 
                // 2. i is occupied => initialized data is being dropped
 
                Some(self.data.get_unchecked_mut(i).as_ptr().read())
 
            }
 
        };
 
        // Mark as vacant...
 
        if i + 1 == self.data.len() {
 
            // ... by truncating self.data.
 
            self.data.pop(); // truncate last data element
 
            let mut walking = i;
 
            while walking > 0 && self.vacant.remove(&(walking - 1)) {
 
                self.data.pop(); // truncate another element
 
                walking -= 1;
 
            }
 
        } else {
 
            // ... by populating self.vacant.
 
            self.vacant.insert(i);
 
        }
 
        value
 
    }
 
    pub fn iter_reserved(&self) -> impl Iterator<Item = usize> + '_ {
 
        self.reserved.iter().copied()
 
    }
 
}
 

	
 
fn pop_set_arb(s: &mut BTreeSet<usize>) -> Option<usize> {
 
    if let Some(&x) = s.iter().next() {
 
        s.remove(&x);
 
        Some(x)
 
    } else {
 
        None
 
    }
 
}
 

	
 
#[test]
 
fn vec_storage() {
 
    #[derive(Debug)]
 
    struct Foo;
 
    impl Drop for Foo {
 
        fn drop(&mut self) {
 
            println!("DROPPING FOO!");
 
        }
 
    }
 

	
 
    let mut v = VecStorage::default();
 
    let i0 = v.new_occupied(Foo);
 
    println!("{:?}", &v);
 
    let i1 = v.new_reserved();
 
    println!("{:?}", &v);
 
    let q = v.vacate(i0);
 
    println!("q {:?}", q);
 
    println!("{:?}", &v);
 
    v.occupy_reserved(i1, Foo);
 
    println!("{:?}", &v);
 
}
src/runtime/experimental/mod.rs
Show inline comments
 
pub mod api;
 
mod api;
 
mod bits;
0 comments (0 inline, 0 general)