use std::fmt::Display;
use std::{num::NonZeroUsize, thread::available_parallelism};
#[repr(C)]
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default, Hash)]
pub enum ThreadingPolicy {
Single,
#[default]
Adaptive,
AdaptiveReserve(NonZeroUsize),
Fixed(NonZeroUsize),
}
impl Display for ThreadingPolicy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ThreadingPolicy::Single => f.write_str("Single"),
ThreadingPolicy::Adaptive => f.write_fmt(format_args!("Adaptive")),
ThreadingPolicy::AdaptiveReserve(size) => {
f.write_fmt(format_args!("AdaptiveReserve({size})"))
}
ThreadingPolicy::Fixed(fixed) => f.write_fmt(format_args!("Fixed({})", fixed.get())),
}
}
}
impl ThreadingPolicy {
pub fn thread_count(&self, width: u32, height: u32) -> usize {
match self {
ThreadingPolicy::Single => 1,
ThreadingPolicy::Adaptive => {
((width * height / (256 * 256)) as usize).clamp(1, Self::available_parallelism(2))
}
ThreadingPolicy::AdaptiveReserve(reserve) => {
let reserve = reserve.get();
let max_threads = {
let max_threads = Self::available_parallelism(1);
if max_threads <= reserve {
1
} else {
max_threads
}
};
((width * height / (256 * 256)) as usize)
.clamp(1, max_threads.min(max_threads - reserve))
}
ThreadingPolicy::Fixed(fixed) => fixed.get(),
}
}
fn available_parallelism(min: usize) -> usize {
available_parallelism()
.unwrap_or_else(|_| NonZeroUsize::new(1).unwrap())
.get()
.max(min)
}
}