use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
pub fn worker_count() -> usize {
std::env::var("LBZIP2_THREADS")
.ok()
.and_then(|v| v.parse::<usize>().ok())
.unwrap_or_else(|| {
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(4)
})
.max(1)
}
pub fn par_map<T, F>(n: usize, f: F) -> Vec<T>
where
T: Send,
F: Fn(usize) -> T + Sync,
{
if n == 0 {
return Vec::new();
}
let threads = worker_count().min(n);
if threads <= 1 {
return (0..n).map(f).collect();
}
let next = AtomicUsize::new(0);
let slots: Vec<Mutex<Option<T>>> = (0..n).map(|_| Mutex::new(None)).collect();
let next_ref = &next;
let slots_ref = &slots;
let f_ref = &f;
std::thread::scope(|s| {
for _ in 0..threads {
s.spawn(move || loop {
let i = next_ref.fetch_add(1, Ordering::Relaxed);
if i >= n {
break;
}
let v = f_ref(i);
*slots_ref[i].lock().unwrap() = Some(v);
});
}
});
slots
.into_iter()
.map(|m| m.into_inner().unwrap().expect("slot filled"))
.collect()
}