use std::collections::{BinaryHeap, VecDeque};
use std::sync::{atomic, Arc};
use educe::Educe;
pub trait HasStaticPriority: Ord {}
impl<P: Ord> HasStaticPriority for P {}
pub trait HasDynamicPriority {
type Value: Ord;
fn priority(&self) -> Self::Value;
}
macro_rules! impl_priority_copy_self {
($self_type:ty) => {
impl HasDynamicPriority for $self_type {
type Value = $self_type;
#[inline]
fn priority(&self) -> Self::Value {
*self
}
}
};
}
impl_priority_copy_self!(i8);
impl_priority_copy_self!(i16);
impl_priority_copy_self!(i32);
impl_priority_copy_self!(i64);
impl_priority_copy_self!(isize);
impl_priority_copy_self!(u8);
impl_priority_copy_self!(u16);
impl_priority_copy_self!(u32);
impl_priority_copy_self!(u64);
impl_priority_copy_self!(usize);
impl<P: HasDynamicPriority> HasDynamicPriority for Arc<P> {
type Value = P::Value;
#[inline]
fn priority(&self) -> Self::Value {
(**self).priority()
}
}
macro_rules! impl_priority_wrapper_method {
($wrapper_type:ty, $method:ident) => {
impl<P: HasDynamicPriority> HasDynamicPriority for $wrapper_type {
type Value = P::Value;
#[inline]
fn priority(&self) -> Self::Value {
self.$method().priority()
}
}
};
}
impl_priority_wrapper_method!(parking_lot::Mutex<P>, lock);
impl_priority_wrapper_method!(parking_lot::RwLock<P>, read);
impl_priority_wrapper_method!(smol::lock::Mutex<P>, lock_blocking);
impl_priority_wrapper_method!(smol::lock::RwLock<P>, read_blocking);
macro_rules! impl_priority_atomic {
($atomic_type:ty, $int_type:ty) => {
impl HasDynamicPriority for $atomic_type {
type Value = $int_type;
#[inline]
fn priority(&self) -> Self::Value {
self.load(atomic::Ordering::Relaxed)
}
}
};
}
impl_priority_atomic!(atomic::AtomicI8, i8);
impl_priority_atomic!(atomic::AtomicI16, i16);
impl_priority_atomic!(atomic::AtomicI32, i32);
impl_priority_atomic!(atomic::AtomicI64, i64);
impl_priority_atomic!(atomic::AtomicIsize, isize);
impl_priority_atomic!(atomic::AtomicU8, u8);
impl_priority_atomic!(atomic::AtomicU16, u16);
impl_priority_atomic!(atomic::AtomicU32, u32);
impl_priority_atomic!(atomic::AtomicU64, u64);
impl_priority_atomic!(atomic::AtomicUsize, usize);
pub trait PriorityQueue<T> {
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn peek(&self) -> Option<&T>;
fn push(&mut self, value: T);
fn pop(&mut self) -> Option<T>;
fn swap_if_higher(&mut self, value: T) -> T;
}
#[derive(Educe)]
#[educe(Default)]
pub struct FifoQueue<T>(VecDeque<T>);
impl<T> PriorityQueue<T> for FifoQueue<T> {
#[inline]
fn len(&self) -> usize {
self.0.len()
}
#[inline]
fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
fn peek(&self) -> Option<&T> {
self.0.front()
}
#[inline]
fn push(&mut self, value: T) {
self.0.push_back(value)
}
#[inline]
fn pop(&mut self) -> Option<T> {
self.0.pop_front()
}
#[inline]
fn swap_if_higher(&mut self, value: T) -> T {
value
}
}
impl<T> From<Vec<T>> for FifoQueue<T> {
#[inline]
fn from(value: Vec<T>) -> Self {
Self(VecDeque::from(value))
}
}
impl<T> FromIterator<T> for FifoQueue<T> {
#[inline]
fn from_iter<II: IntoIterator<Item=T>>(iter: II) -> Self {
Self::from(iter.into_iter().collect::<Vec<_>>())
}
}
impl<T, const N: usize> From<[T; N]> for FifoQueue<T> {
#[inline]
fn from(value: [T; N]) -> Self {
Self::from_iter(value)
}
}
#[derive(Educe)]
#[educe(Default)]
pub struct StaticPriorityQueue<T: HasStaticPriority> {
inner: BinaryHeap<T>,
}
impl<T: HasStaticPriority> PriorityQueue<T> for StaticPriorityQueue<T> {
#[inline]
fn len(&self) -> usize {
self.inner.len()
}
#[inline]
fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
fn peek(&self) -> Option<&T> {
self.inner.peek()
}
#[inline]
fn push(&mut self, value: T) {
self.inner.push(value)
}
#[inline]
fn pop(&mut self) -> Option<T> {
self.inner.pop()
}
fn swap_if_higher(&mut self, value: T) -> T {
if let Some(highest) = self.inner.peek() && highest > &value {
let new_value = self.inner.pop().unwrap();
self.inner.push(value);
new_value
} else {
value
}
}
}
impl<T: HasStaticPriority> From<Vec<T>> for StaticPriorityQueue<T> {
#[inline]
fn from(value: Vec<T>) -> Self {
Self {
inner: BinaryHeap::from(value)
}
}
}
impl<T: HasStaticPriority> FromIterator<T> for StaticPriorityQueue<T> {
#[inline]
fn from_iter<II: IntoIterator<Item=T>>(iter: II) -> Self {
Self::from(iter.into_iter().collect::<Vec<_>>())
}
}
impl<T: HasStaticPriority, const N: usize> From<[T; N]> for StaticPriorityQueue<T> {
#[inline]
fn from(value: [T; N]) -> Self {
Self::from_iter(value)
}
}
#[derive(Educe)]
#[educe(Default)]
pub struct DynamicPriorityQueue<T: HasDynamicPriority> {
inner: Vec<T>,
}
impl<T: HasDynamicPriority> DynamicPriorityQueue<T> {
fn find_highest(&self) -> Option<(usize, &T, T::Value)> {
let mut highest: Option<(usize, &T, T::Value)> = None;
for (idx, value) in self.inner.iter().enumerate() {
let priority = value.priority();
match highest {
Some((_, _, ref highest_priority)) => {
if &priority > highest_priority {
highest = Some((idx, value, priority));
}
},
None => {
highest = Some((idx, value, priority));
},
}
}
highest
}
}
impl<T: HasDynamicPriority> PriorityQueue<T> for DynamicPriorityQueue<T> {
#[inline]
fn len(&self) -> usize {
self.inner.len()
}
#[inline]
fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
fn peek(&self) -> Option<&T> {
self.find_highest().map(|(_, value, _)| value)
}
#[inline]
fn push(&mut self, value: T) {
self.inner.push(value)
}
#[inline]
fn pop(&mut self) -> Option<T> {
self.find_highest()
.map(|(idx, _, _)| idx)
.map(|idx| self.inner.swap_remove(idx))
}
fn swap_if_higher(&mut self, value: T) -> T {
let priority = value.priority();
let highest = self.find_highest().map(|(idx, _, priority)| (idx, priority));
if let Some((idx, highest_priority)) = highest && highest_priority > priority {
let new_value = self.inner.swap_remove(idx);
self.inner.push(value);
new_value
} else {
value
}
}
}
impl<T: HasDynamicPriority> From<Vec<T>> for DynamicPriorityQueue<T> {
#[inline]
fn from(value: Vec<T>) -> Self {
Self {
inner: value,
}
}
}
impl<T: HasDynamicPriority> FromIterator<T> for DynamicPriorityQueue<T> {
#[inline]
fn from_iter<II: IntoIterator<Item=T>>(iter: II) -> Self {
Self::from(iter.into_iter().collect::<Vec<_>>())
}
}
impl<T: HasDynamicPriority, const N: usize> From<[T; N]> for DynamicPriorityQueue<T> {
#[inline]
fn from(value: [T; N]) -> Self {
Self::from_iter(value)
}
}