diff --git a/Cargo.toml b/Cargo.toml index 6fff4e6b..f49a0556 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,19 +21,20 @@ cirrus-ci = { repository = "jonhoo/inferno" } codecov = { repository = "jonhoo/inferno", branch = "master", service = "github" } [features] -default = ["cli"] +default = ["cli", "multithreaded"] cli = ["structopt", "env_logger"] +multithreaded = ["chashmap", "crossbeam", "num_cpus"] [dependencies] -chashmap = "2.2" -crossbeam = "0.7" +chashmap = { version = "2.2", optional = true } +crossbeam = { version = "0.7", optional = true } env_logger = { version = "0.6.0", optional = true } fnv = "1.0.3" indexmap = "1.0" itoa = "0.4.3" lazy_static = "1.3.0" log = "0.4" -num_cpus = "1.10" +num_cpus = { version = "1.10", optional = true } num-format = { version = "0.4", default-features = false } quick-xml = { version = "0.16", default-features = false } rgb = "0.8.13" diff --git a/src/collapse/common.rs b/src/collapse/common.rs index ada5c994..515d49da 100644 --- a/src/collapse/common.rs +++ b/src/collapse/common.rs @@ -3,8 +3,11 @@ use std::io; use std::mem; use std::sync::Arc; +#[cfg(feature = "multithreaded")] use chashmap::CHashMap; +#[cfg(feature = "multithreaded")] use crossbeam::channel; + use fnv::FnvHashMap; use lazy_static::lazy_static; @@ -26,11 +29,18 @@ const NBYTES_PER_STACK_GUESS: usize = 1024; const RUST_HASH_LENGTH: usize = 17; +#[cfg(feature = "multithreaded")] lazy_static! { #[doc(hidden)] pub static ref DEFAULT_NTHREADS: usize = num_cpus::get(); } +#[cfg(not(feature = "multithreaded"))] +lazy_static! { + #[doc(hidden)] + pub static ref DEFAULT_NTHREADS: usize = 1; +} + /// Private trait for internal library authors. /// /// If you implement this trait, your type will implement the public-facing @@ -154,6 +164,19 @@ pub trait CollapsePrivate: Send + Sized { occurrences.write_and_clear(writer) } + #[cfg(not(feature = "multithreaded"))] + fn collapse_multi_threaded( + &mut self, + _: R, + _: &mut Occurrences, + ) -> io::Result<()> + where + R: io::BufRead, + { + unimplemented!(); + } + + #[cfg(feature = "multithreaded")] fn collapse_multi_threaded( &mut self, mut reader: R, @@ -332,25 +355,42 @@ pub trait CollapsePrivate: Send + Sized { #[derive(Clone, Debug)] pub enum Occurrences { SingleThreaded(FnvHashMap), + #[cfg(feature = "multithreaded")] MultiThreaded(Arc>), } impl Occurrences { + #[cfg(feature = "multithreaded")] pub(crate) fn new(nthreads: usize) -> Self { assert_ne!(nthreads, 0); if nthreads == 1 { - let map = FnvHashMap::with_capacity_and_hasher( - CAPACITY_HASHMAP, - fnv::FnvBuildHasher::default(), - ); - Occurrences::SingleThreaded(map) + Self::new_single_threaded() } else { - let map = CHashMap::with_capacity(CAPACITY_HASHMAP); - let arc = Arc::new(map); - Occurrences::MultiThreaded(arc) + Self::new_multi_threaded() } } + #[cfg(not(feature = "multithreaded"))] + pub(crate) fn new(nthreads: usize) -> Self { + assert_ne!(nthreads, 0); + Self::new_single_threaded() + } + + fn new_single_threaded() -> Self { + let map = FnvHashMap::with_capacity_and_hasher( + CAPACITY_HASHMAP, + fnv::FnvBuildHasher::default(), + ); + Occurrences::SingleThreaded(map) + } + + #[cfg(feature = "multithreaded")] + fn new_multi_threaded() -> Self { + let map = CHashMap::with_capacity(CAPACITY_HASHMAP); + let arc = Arc::new(map); + Occurrences::MultiThreaded(arc) + } + /// Inserts a key-count pair into the map. If the map did not have this key /// present, `None` is returned. If the map did have this key present, the /// value is updated, and the old value is returned. @@ -358,6 +398,7 @@ impl Occurrences { use self::Occurrences::*; match self { SingleThreaded(map) => map.insert(key, count), + #[cfg(feature = "multithreaded")] MultiThreaded(arc) => arc.insert(key, count), } } @@ -369,6 +410,7 @@ impl Occurrences { use self::Occurrences::*; match self { SingleThreaded(map) => *map.entry(key).or_insert(0) += count, + #[cfg(feature = "multithreaded")] MultiThreaded(arc) => arc.upsert(key, || count, |v| *v += count), } } @@ -377,6 +419,7 @@ impl Occurrences { use self::Occurrences::*; match self { SingleThreaded(_) => false, + #[cfg(feature = "multithreaded")] MultiThreaded(_) => true, } } @@ -394,6 +437,7 @@ impl Occurrences { writeln!(writer, "{} {}", key, value)?; } } + #[cfg(feature = "multithreaded")] MultiThreaded(ref mut arc) => { let map = match Arc::get_mut(arc) { Some(map) => map,