use core::ops::Range;
#[cfg(feature = "rayon")]
pub(crate) fn map_ranges<T: Send>(n: usize, f: impl Fn(Range<usize>) -> T + Sync + Send) -> Vec<T> {
use rayon::prelude::*;
let threads = rayon::current_num_threads().max(1);
let chunks = if n < 4096 {
1
} else {
(threads * 8).min(n / 512).max(1)
};
if chunks == 1 {
return vec![f(0..n)];
}
let size = n.div_ceil(chunks).max(1);
(0..chunks)
.into_par_iter()
.map(|k| f((k * size).min(n)..((k + 1) * size).min(n)))
.collect()
}
#[cfg(not(feature = "rayon"))]
pub(crate) fn map_ranges<T: Send>(n: usize, f: impl Fn(Range<usize>) -> T + Sync + Send) -> Vec<T> {
vec![f(0..n)]
}
pub(crate) fn map_chunks<T: Send>(
n: usize,
chunks: usize,
f: impl Fn(Range<usize>) -> T + Sync + Send,
) -> Vec<T> {
let chunks = chunks.max(1);
let size = n.div_ceil(chunks).max(1);
let range = |k: usize| (k * size).min(n)..((k + 1) * size).min(n);
#[cfg(feature = "rayon")]
if chunks > 1 {
use rayon::prelude::*;
return (0..chunks).into_par_iter().map(|k| f(range(k))).collect();
}
(0..chunks).map(|k| f(range(k))).collect()
}
pub(crate) fn concat<P: Sync, T: Copy + Send + Sync>(
parts: &[P],
part: impl Fn(&P) -> &[T] + Sync,
) -> Vec<T> {
let mut start = Vec::with_capacity(parts.len() + 1);
start.push(0usize);
for p in parts {
start.push(start.last().unwrap_or(&0) + part(p).len());
}
let total = *start.last().unwrap_or(&0);
#[cfg(feature = "rayon")]
if total >= 1 << 16 && parts.len() > 1 {
use rayon::prelude::*;
let mut out = Vec::with_capacity(total);
(0..total)
.into_par_iter()
.with_min_len(1 << 12)
.map_init(
|| usize::MAX,
|p, i| {
if *p >= parts.len() || i < start[*p] {
*p = start.partition_point(|&s| s <= i) - 1;
}
while start[*p + 1] <= i {
*p += 1;
}
part(&parts[*p])[i - start[*p]]
},
)
.collect_into_vec(&mut out);
return out;
}
let mut out = Vec::with_capacity(total);
for p in parts {
out.extend_from_slice(part(p));
}
out
}
pub(crate) fn concat_vecs<T: Copy + Send + Sync>(parts: Vec<Vec<T>>) -> Vec<T> {
if parts.len() == 1 {
return parts.into_iter().next().unwrap_or_default();
}
#[cfg(feature = "rayon")]
{
concat(&parts, |p| &p[..])
}
#[cfg(not(feature = "rayon"))]
{
let mut out = Vec::with_capacity(parts.iter().map(|p| p.len()).sum());
for p in parts {
out.extend_from_slice(&p);
}
out
}
}
pub(crate) fn map_vec<T: Send, U: Send>(items: Vec<T>, f: impl Fn(T) -> U + Sync + Send) -> Vec<U> {
#[cfg(feature = "rayon")]
if items.len() > 1 {
use rayon::prelude::*;
return items.into_par_iter().map(f).collect();
}
items.into_iter().map(f).collect()
}
pub(crate) fn map_slice<T: Sync, U: Send>(
items: &[T],
f: impl Fn(&T) -> U + Sync + Send,
) -> Vec<U> {
#[cfg(feature = "rayon")]
if items.len() >= 1 << 16 {
use rayon::prelude::*;
return items.par_iter().with_min_len(1 << 12).map(f).collect();
}
items.iter().map(f).collect()
}
#[cfg(feature = "rayon")]
pub(crate) fn map_items<T: Sync, U: Send>(
items: &[T],
f: impl Fn(&T) -> U + Sync + Send,
) -> Vec<U> {
use rayon::prelude::*;
if items.len() <= 1 {
return items.iter().map(f).collect();
}
items.par_iter().map(f).collect()
}
#[cfg(not(feature = "rayon"))]
pub(crate) fn map_items<T: Sync, U: Send>(
items: &[T],
f: impl Fn(&T) -> U + Sync + Send,
) -> Vec<U> {
items.iter().map(f).collect()
}
#[cfg(feature = "rayon")]
pub(crate) fn threads() -> usize {
rayon::current_num_threads().max(1)
}
#[cfg(not(feature = "rayon"))]
pub(crate) fn threads() -> usize {
1
}
pub(crate) fn sort_unstable<T: Ord + Send>(v: &mut [T]) {
#[cfg(feature = "rayon")]
if v.len() >= 1 << 15 {
use rayon::prelude::*;
v.par_sort_unstable();
return;
}
v.sort_unstable();
}
pub(crate) fn bucket_sort_by_x<T: Copy + Default + Send + Sync>(
v: Vec<T>,
x: impl Fn(&T) -> i64 + Sync,
cmp: impl Fn(&T, &T) -> core::cmp::Ordering + Sync,
) -> Vec<T> {
let n = v.len();
if n < 1 << 14 {
let mut v = v;
v.sort_unstable_by(cmp);
return v;
}
let (lo, hi) = v
.iter()
.fold((i64::MAX, i64::MIN), |(l, h), e| (l.min(x(e)), h.max(x(e))));
let span = (hi as i128 - lo as i128) as u128;
let mut shift = 0u32;
while (span >> shift) as usize >= (n / 8).max(1) {
shift += 1;
}
let nb = (span >> shift) as usize + 1;
let bucket = |e: &T| ((x(e) as i128 - lo as i128) as u128 >> shift) as usize;
let mut start = vec![0usize; nb + 1];
for e in &v {
start[bucket(e) + 1] += 1;
}
for i in 0..nb {
start[i + 1] += start[i];
}
let mut pos = start.clone();
let mut out = vec![T::default(); n];
for e in &v {
let b = bucket(e);
out[pos[b]] = *e;
pos[b] += 1;
}
drop(v);
sort_buckets(&mut out, &start, &cmp);
out
}
#[cfg(feature = "rayon")]
fn sort_buckets<T: Send>(
out: &mut [T],
start: &[usize],
cmp: &(impl Fn(&T, &T) -> core::cmp::Ordering + Sync),
) {
use rayon::prelude::*;
let n = out.len();
let chunks = (rayon::current_num_threads() * 8).max(1);
let mut cuts: Vec<usize> = (1..chunks)
.map(|k| {
start[start
.partition_point(|&s| s < k * n / chunks)
.min(start.len() - 1)]
})
.collect();
cuts.dedup();
let mut parts: Vec<(&mut [T], usize)> = Vec::new();
let mut rest = out;
let mut base = 0usize;
for c in cuts {
if c <= base || c >= n {
continue;
}
let (a, b) = rest.split_at_mut(c - base);
parts.push((a, base));
rest = b;
base = c;
}
parts.push((rest, base));
parts.into_par_iter().for_each(|(part, base)| {
let end = base + part.len();
let first = start.partition_point(|&s| s <= base) - 1;
let mut b = first;
while b + 1 < start.len() && start[b] < end {
let (s, e) = (start[b].max(base) - base, start[b + 1].min(end) - base);
if e > s + 1 {
part[s..e].sort_unstable_by(cmp);
}
b += 1;
}
});
}
#[cfg(not(feature = "rayon"))]
fn sort_buckets<T>(out: &mut [T], start: &[usize], cmp: &impl Fn(&T, &T) -> core::cmp::Ordering) {
for w in start.windows(2) {
if w[1] > w[0] + 1 {
out[w[0]..w[1]].sort_unstable_by(cmp);
}
}
}