diff --git a/crossbeam-epoch/Cargo.toml b/crossbeam-epoch/Cargo.toml index 16d447578..79e0f5ec9 100644 --- a/crossbeam-epoch/Cargo.toml +++ b/crossbeam-epoch/Cargo.toml @@ -17,7 +17,7 @@ categories = ["concurrency", "memory-management", "no-std"] [features] default = ["std"] -nightly = ["crossbeam-utils/nightly", "arrayvec/use_union"] +nightly = ["crossbeam-utils/nightly"] std = ["crossbeam-utils/std", "lazy_static"] alloc = ["crossbeam-utils/alloc"] sanitize = [] # Makes it more likely to trigger any potential data races. @@ -26,10 +26,6 @@ sanitize = [] # Makes it more likely to trigger any potential data races. cfg-if = "0.1.2" memoffset = "0.5" -[dependencies.arrayvec] -version = "0.4" -default-features = false - [dependencies.crossbeam-utils] version = "0.6" path = "../crossbeam-utils" diff --git a/crossbeam-epoch/src/internal.rs b/crossbeam-epoch/src/internal.rs index 819e6bdc1..d43e2b766 100644 --- a/crossbeam-epoch/src/internal.rs +++ b/crossbeam-epoch/src/internal.rs @@ -38,11 +38,10 @@ use core::cell::{Cell, UnsafeCell}; use core::mem::{self, ManuallyDrop}; use core::num::Wrapping; -use core::ptr; +use core::{ptr, fmt}; use core::sync::atomic; use core::sync::atomic::Ordering; -use arrayvec::ArrayVec; use crossbeam_utils::CachePadded; use atomic::{Shared, Owned}; @@ -60,10 +59,10 @@ const MAX_OBJECTS: usize = 64; const MAX_OBJECTS: usize = 4; /// A bag of deferred functions. -#[derive(Default, Debug)] pub struct Bag { /// Stashed objects. - deferreds: ArrayVec<[Deferred; MAX_OBJECTS]>, + deferreds: [Deferred; MAX_OBJECTS], + len: usize } /// `Bag::try_push()` requires that it is safe for another thread to execute the given functions. @@ -77,7 +76,7 @@ impl Bag { /// Returns `true` if the bag is empty. pub fn is_empty(&self) -> bool { - self.deferreds.is_empty() + self.len == 0 } /// Attempts to insert a deferred function into the bag. @@ -89,7 +88,13 @@ impl Bag { /// /// It should be safe for another thread to execute the given function. pub unsafe fn try_push(&mut self, deferred: Deferred) -> Result<(), Deferred> { - self.deferreds.try_push(deferred).map_err(|e| e.element()) + if self.len < MAX_OBJECTS { + self.deferreds[self.len] = deferred; + self.len += 1; + Ok(()) + } else { + Err(deferred) + } } /// Seals the bag with the given epoch. @@ -98,15 +103,53 @@ impl Bag { } } +impl Default for Bag { + fn default() -> Self { + // TODO: [no_op; MAX_OBJECTS] syntax blocked by https://github.com/rust-lang/rust/issues/49147 + #[cfg(not(feature = "sanitize"))] + return Bag { len: 0, deferreds: + [Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), + Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func)] + }; + #[cfg(feature = "sanitize")] + return Bag { len: 0, deferreds: [Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func), Deferred::new(no_op_func)] }; + } +} + impl Drop for Bag { fn drop(&mut self) { // Call all deferred functions. - for deferred in self.deferreds.drain(..) { + for i in 0..self.len { + let no_op = Deferred::new(no_op_func); + let deferred = mem::replace(&mut self.deferreds[i], no_op); deferred.call(); } } } +// can't #[derive(Debug)] because Debug is not implemented for arrays 64 items long +impl fmt::Debug for Bag { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Bag").field("deferreds", &&self.deferreds[..self.len]).finish() + } +} + +fn no_op_func() {} + /// A pair of an epoch and a bag. #[derive(Default, Debug)] struct SealedBag { diff --git a/crossbeam-epoch/src/lib.rs b/crossbeam-epoch/src/lib.rs index 8ff4bfd30..e3116dcf7 100644 --- a/crossbeam-epoch/src/lib.rs +++ b/crossbeam-epoch/src/lib.rs @@ -79,7 +79,6 @@ cfg_if! { )] cfg_if! { if #[cfg(any(feature = "alloc", feature = "std"))] { - extern crate arrayvec; extern crate crossbeam_utils; #[macro_use] extern crate memoffset;