diff --git a/src/runtime2/store/component.rs b/src/runtime2/store/component.rs index d5dc283cdb2a376c8286b7eef849feb9f4c85c66..cd35878591ace87d2922fd5483a73d85c508fdd8 100644 --- a/src/runtime2/store/component.rs +++ b/src/runtime2/store/component.rs @@ -43,6 +43,8 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use super::unfair_se_lock::{UnfairSeLock, UnfairSeLockSharedGuard}; +/// Generic store of components. Essentially a resizable freelist (implemented +/// as a ringbuffer) combined with an array of actual elements. pub struct ComponentStore { inner: UnfairSeLock>, read_head: AtomicUsize, @@ -53,6 +55,8 @@ pub struct ComponentStore { unsafe impl Send for ComponentStore{} unsafe impl Sync for ComponentStore{} +/// Contents of the `ComponentStore` that require a shared/exclusive locking +/// mechanism for consistency. struct Inner { freelist: Vec, data: Vec<*mut T>, @@ -63,6 +67,29 @@ struct Inner { type InnerShared<'a, T> = UnfairSeLockSharedGuard<'a, Inner>; +/// Reservation of a slot in the component store. Corresponds to the case where +/// an index has been taken from the freelist, but the element has not yet been +/// initialized +pub struct ComponentReservation { + pub(crate) index: u32, + #[cfg(debug_assertions)] submitted: bool, +} + +impl ComponentReservation { + fn new(index: u32) -> Self { + return Self{ + index, + #[cfg(debug_assertions)] submitted: false, + } + } +} + +impl Drop for ComponentReservation { + fn drop(&mut self) { + debug_assert!(self.submitted); + } +} + impl ComponentStore { pub fn new(initial_size: usize) -> Self { Self::assert_valid_size(initial_size); @@ -96,10 +123,23 @@ impl ComponentStore { pub fn create(&self, value: T) -> u32 { let lock = self.inner.lock_shared(); let (lock, index) = self.pop_freelist_index(lock); - self.initialize_at_index(lock, index, value); + Self::initialize_at_index(lock, index, value); return index; } + pub fn reserve(&self) -> ComponentReservation { + let lock = self.inner.lock_shared(); + let (lock, index) = self.pop_freelist_index(lock); + return ComponentReservation::new(index); + } + + pub fn submit(&self, mut reservation: ComponentReservation, value: T) -> u32 { + dbg_code!({ reservation.submitted = true; }); + let lock = self.inner.lock_shared(); + Self::initialize_at_index(lock, reservation.index, value); + return reservation.index; + } + /// Destroys an element at the provided `index`. The caller must make sure /// that it does not use any previously received references to the data at /// this index, and that no more calls to `get` are performed using this @@ -163,7 +203,7 @@ impl ComponentStore { } #[inline] - fn initialize_at_index(&self, read_lock: InnerShared, index: u32, value: T) { + fn initialize_at_index(read_lock: InnerShared, index: u32, value: T) { let mut target_ptr = read_lock.data[index as usize]; unsafe {