浏览代码

refac: remove special empty state from slots (#25)

This isn't necessary, as we can use a const while loop
to fill in the slots with correct indices.

This makes the push and pop code a little simpler, which
may also improve performance!

Signed-off-by: Eliza Weisman <[email protected]>
Eliza Weisman 3 年之前
父节点
当前提交
63825e6c53
共有 5 个文件被更改,包括 32 次插入29 次删除
  1. 26 14
      src/lib.rs
  2. 2 5
      src/mpsc/async_impl.rs
  3. 2 5
      src/mpsc/sync.rs
  4. 1 3
      src/static_thingbuf.rs
  5. 1 2
      src/thingbuf.rs

+ 26 - 14
src/lib.rs

@@ -159,14 +159,9 @@ impl Core {
             test_dbg!(idx);
             test_dbg!(gen);
             let slot = &slots[idx];
-            let actual_state = test_dbg!(slot.state.load(Acquire));
-            let state = if actual_state == EMPTY_STATE {
-                idx
-            } else {
-                actual_state
-            };
+            let state = test_dbg!(slot.state.load(Acquire));
 
-            if test_dbg!(state == tail) || test_dbg!(actual_state == EMPTY_STATE && gen == 0) {
+            if test_dbg!(state == tail) {
                 // Move the tail index forward by 1.
                 let next_tail = self.next(idx, gen);
                 match test_dbg!(self
@@ -243,7 +238,6 @@ impl Core {
             test_dbg!(gen);
             let slot = &slots[idx];
             let state = test_dbg!(slot.state.load(Acquire));
-            let state = if state == EMPTY_STATE { idx } else { state };
 
             // If the slot's state is ahead of the head index by one, we can pop
             // it.
@@ -416,22 +410,40 @@ unsafe impl<T: Send> Sync for Ref<'_, T> {}
 
 // === impl Slot ===
 
-const EMPTY_STATE: usize = usize::MAX;
-
 impl<T> Slot<T> {
+    #[cfg(feature = "alloc")]
+    pub(crate) fn make_boxed_array(capacity: usize) -> Box<[Self]> {
+        (0..capacity).map(|i| Slot::new(i)).collect()
+    }
+
+    #[cfg(not(all(loom, test)))]
+    const EMPTY: Self = Self::new(usize::MAX);
+
+    #[cfg(not(all(loom, test)))]
+    pub(crate) const fn make_static_array<const CAPACITY: usize>() -> [Self; CAPACITY] {
+        let mut array = [Self::EMPTY; CAPACITY];
+        let mut i = 0;
+        while i < CAPACITY {
+            array[i] = Self::new(i);
+            i += 1;
+        }
+
+        array
+    }
+
     #[cfg(not(all(loom, test)))]
-    const fn empty() -> Self {
+    const fn new(idx: usize) -> Self {
         Self {
             value: UnsafeCell::new(MaybeUninit::uninit()),
-            state: AtomicUsize::new(EMPTY_STATE),
+            state: AtomicUsize::new(idx),
         }
     }
 
     #[cfg(all(loom, test))]
-    fn empty() -> Self {
+    fn new(idx: usize) -> Self {
         Self {
             value: UnsafeCell::new(MaybeUninit::uninit()),
-            state: AtomicUsize::new(EMPTY_STATE),
+            state: AtomicUsize::new(idx),
         }
     }
 }

+ 2 - 5
src/mpsc/async_impl.rs

@@ -19,10 +19,9 @@ feature! {
     /// Returns a new synchronous multi-producer, single consumer channel.
     pub fn channel<T: Default>(capacity: usize) -> (Sender<T>, Receiver<T>) {
         assert!(capacity > 0);
-        let slots = (0..capacity).map(|_| Slot::empty()).collect();
         let inner = Arc::new(Inner {
             core: ChannelCore::new(capacity),
-            slots,
+            slots: Slot::make_boxed_array(capacity),
         });
         let tx = Sender {
             inner: inner.clone(),
@@ -147,8 +146,6 @@ enum State {
 
 #[cfg(not(all(loom, test)))]
 impl<T, const CAPACITY: usize> StaticChannel<T, CAPACITY> {
-    const SLOT: Slot<T> = Slot::empty();
-
     /// Constructs a new statically-allocated, asynchronous bounded MPSC channel.
     ///
     /// A statically-allocated channel allows using a MPSC channel without
@@ -183,7 +180,7 @@ impl<T, const CAPACITY: usize> StaticChannel<T, CAPACITY> {
     pub const fn new() -> Self {
         Self {
             core: ChannelCore::new(CAPACITY),
-            slots: [Self::SLOT; CAPACITY],
+            slots: Slot::make_static_array::<CAPACITY>(),
             is_split: AtomicBool::new(false),
         }
     }

+ 2 - 5
src/mpsc/sync.rs

@@ -17,10 +17,9 @@ use core::{fmt, pin::Pin};
 
 /// Returns a new asynchronous multi-producer, single consumer channel.
 pub fn channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) {
-    let slots = (0..capacity).map(|_| Slot::empty()).collect();
     let inner = Arc::new(Inner {
         core: ChannelCore::new(capacity),
-        slots,
+        slots: Slot::make_boxed_array(capacity),
     });
     let tx = Sender {
         inner: inner.clone(),
@@ -110,8 +109,6 @@ impl_recv_ref! {
 
 #[cfg(not(all(loom, test)))]
 impl<T, const CAPACITY: usize> StaticChannel<T, CAPACITY> {
-    const SLOT: Slot<T> = Slot::empty();
-
     /// Constructs a new statically-allocated, blocking bounded MPSC channel.
     ///
     /// A statically-allocated channel allows using a MPSC channel without
@@ -153,7 +150,7 @@ impl<T, const CAPACITY: usize> StaticChannel<T, CAPACITY> {
     pub const fn new() -> Self {
         Self {
             core: ChannelCore::new(CAPACITY),
-            slots: [Self::SLOT; CAPACITY],
+            slots: Slot::make_static_array::<CAPACITY>(),
             is_split: AtomicBool::new(false),
         }
     }

+ 1 - 3
src/static_thingbuf.rs

@@ -11,12 +11,10 @@ pub struct StaticThingBuf<T, const CAP: usize> {
 
 #[cfg(not(test))]
 impl<T, const CAP: usize> StaticThingBuf<T, CAP> {
-    const SLOT: Slot<T> = Slot::empty();
-
     pub const fn new() -> Self {
         Self {
             core: Core::new(CAP),
-            slots: [Self::SLOT; CAP],
+            slots: Slot::make_static_array::<CAP>(),
         }
     }
 }

+ 1 - 2
src/thingbuf.rs

@@ -17,10 +17,9 @@ pub struct ThingBuf<T> {
 impl<T: Default> ThingBuf<T> {
     pub fn new(capacity: usize) -> Self {
         assert!(capacity > 0);
-        let slots = (0..capacity).map(|_| Slot::empty()).collect();
         Self {
             core: Core::new(capacity),
-            slots,
+            slots: Slot::make_boxed_array(capacity),
         }
     }