use core::cmp::Ordering;
use core::fmt;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
use core::ptr;
pub trait SortedLinkedListIndex: Copy {
#[doc(hidden)]
unsafe fn new_unchecked(val: usize) -> Self;
#[doc(hidden)]
unsafe fn get_unchecked(self) -> usize;
#[doc(hidden)]
fn option(self) -> Option<usize>;
#[doc(hidden)]
fn none() -> Self;
}
pub struct Min;
pub struct Max;
pub trait Kind: private::Sealed {
#[doc(hidden)]
fn ordering() -> Ordering;
}
impl Kind for Min {
fn ordering() -> Ordering {
Ordering::Less
}
}
impl Kind for Max {
fn ordering() -> Ordering {
Ordering::Greater
}
}
mod private {
pub trait Sealed {}
}
impl private::Sealed for Max {}
impl private::Sealed for Min {}
pub struct Node<T, Idx> {
val: MaybeUninit<T>,
next: Idx,
}
pub struct SortedLinkedList<T, Idx, K, const N: usize>
where
Idx: SortedLinkedListIndex,
{
list: [Node<T, Idx>; N],
head: Idx,
free: Idx,
_kind: PhantomData<K>,
}
macro_rules! impl_index_and_const_new {
($name:ident, $ty:ty, $new_name:ident, $max_val:expr) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct $name($ty);
impl SortedLinkedListIndex for $name {
#[inline(always)]
unsafe fn new_unchecked(val: usize) -> Self {
Self::new_unchecked(val as $ty)
}
#[inline(always)]
unsafe fn get_unchecked(self) -> usize {
self.0 as usize
}
#[inline(always)]
fn option(self) -> Option<usize> {
if self.0 == <$ty>::MAX {
None
} else {
Some(self.0 as usize)
}
}
#[inline(always)]
fn none() -> Self {
Self::none()
}
}
impl $name {
#[inline]
const unsafe fn new_unchecked(value: $ty) -> Self {
$name(value)
}
#[inline]
const fn none() -> Self {
$name(<$ty>::MAX)
}
}
impl<T, K, const N: usize> SortedLinkedList<T, $name, K, N> {
const UNINIT: Node<T, $name> = Node {
val: MaybeUninit::uninit(),
next: $name::none(),
};
pub const fn $new_name() -> Self {
crate::sealed::smaller_than::<N, $max_val>();
let mut list = SortedLinkedList {
list: [Self::UNINIT; N],
head: $name::none(),
free: unsafe { $name::new_unchecked(0) },
_kind: PhantomData,
};
if N == 0 {
list.free = $name::none();
return list;
}
let mut free = 0;
while free < N - 1 {
list.list[free].next = unsafe { $name::new_unchecked(free as $ty + 1) };
free += 1;
}
list
}
}
};
}
impl_index_and_const_new!(LinkedIndexU8, u8, new_u8, { u8::MAX as usize - 1 });
impl_index_and_const_new!(LinkedIndexU16, u16, new_u16, { u16::MAX as usize - 1 });
impl_index_and_const_new!(LinkedIndexUsize, usize, new_usize, { usize::MAX - 1 });
impl<T, Idx, K, const N: usize> SortedLinkedList<T, Idx, K, N>
where
Idx: SortedLinkedListIndex,
{
#[inline(always)]
fn node_at(&self, index: usize) -> &Node<T, Idx> {
unsafe { self.list.get_unchecked(index) }
}
#[inline(always)]
fn node_at_mut(&mut self, index: usize) -> &mut Node<T, Idx> {
unsafe { self.list.get_unchecked_mut(index) }
}
#[inline(always)]
fn write_data_in_node_at(&mut self, index: usize, data: T) {
unsafe {
self.node_at_mut(index).val.as_mut_ptr().write(data);
}
}
#[inline(always)]
fn read_data_in_node_at(&self, index: usize) -> &T {
unsafe { &*self.node_at(index).val.as_ptr() }
}
#[inline(always)]
fn read_mut_data_in_node_at(&mut self, index: usize) -> &mut T {
unsafe { &mut *self.node_at_mut(index).val.as_mut_ptr() }
}
#[inline(always)]
fn extract_data_in_node_at(&mut self, index: usize) -> T {
unsafe { self.node_at(index).val.as_ptr().read() }
}
}
impl<T, Idx, K, const N: usize> SortedLinkedList<T, Idx, K, N>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
{
pub unsafe fn push_unchecked(&mut self, value: T) {
let new = self.free.get_unchecked();
self.write_data_in_node_at(new, value);
self.free = self.node_at(new).next;
if let Some(head) = self.head.option() {
if self
.read_data_in_node_at(head)
.cmp(self.read_data_in_node_at(new))
!= K::ordering()
{
self.node_at_mut(new).next = self.head;
self.head = Idx::new_unchecked(new);
} else {
let mut current = head;
while let Some(next) = self.node_at(current).next.option() {
if self
.read_data_in_node_at(next)
.cmp(self.read_data_in_node_at(new))
!= K::ordering()
{
break;
}
current = next;
}
self.node_at_mut(new).next = self.node_at(current).next;
self.node_at_mut(current).next = Idx::new_unchecked(new);
}
} else {
self.node_at_mut(new).next = self.head;
self.head = Idx::new_unchecked(new);
}
}
pub fn push(&mut self, value: T) -> Result<(), T> {
if !self.is_full() {
Ok(unsafe { self.push_unchecked(value) })
} else {
Err(value)
}
}
pub fn iter(&self) -> Iter<'_, T, Idx, K, N> {
Iter {
list: self,
index: self.head,
}
}
pub fn find_mut<F>(&mut self, mut f: F) -> Option<FindMut<'_, T, Idx, K, N>>
where
F: FnMut(&T) -> bool,
{
let head = self.head.option()?;
if f(self.read_data_in_node_at(head)) {
return Some(FindMut {
is_head: true,
prev_index: Idx::none(),
index: self.head,
list: self,
maybe_changed: false,
});
}
let mut current = head;
while let Some(next) = self.node_at(current).next.option() {
if f(self.read_data_in_node_at(next)) {
return Some(FindMut {
is_head: false,
prev_index: unsafe { Idx::new_unchecked(current) },
index: unsafe { Idx::new_unchecked(next) },
list: self,
maybe_changed: false,
});
}
current = next;
}
None
}
pub fn peek(&self) -> Option<&T> {
self.head
.option()
.map(|head| self.read_data_in_node_at(head))
}
pub unsafe fn pop_unchecked(&mut self) -> T {
let head = self.head.get_unchecked();
let current = head;
self.head = self.node_at(head).next;
self.node_at_mut(current).next = self.free;
self.free = Idx::new_unchecked(current);
self.extract_data_in_node_at(current)
}
pub fn pop(&mut self) -> Result<T, ()> {
if !self.is_empty() {
Ok(unsafe { self.pop_unchecked() })
} else {
Err(())
}
}
#[inline]
pub fn is_full(&self) -> bool {
self.free.option().is_none()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.head.option().is_none()
}
}
pub struct Iter<'a, T, Idx, K, const N: usize>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
{
list: &'a SortedLinkedList<T, Idx, K, N>,
index: Idx,
}
impl<'a, T, Idx, K, const N: usize> Iterator for Iter<'a, T, Idx, K, N>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let index = self.index.option()?;
let node = self.list.node_at(index);
self.index = node.next;
Some(self.list.read_data_in_node_at(index))
}
}
pub struct FindMut<'a, T, Idx, K, const N: usize>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
{
list: &'a mut SortedLinkedList<T, Idx, K, N>,
is_head: bool,
prev_index: Idx,
index: Idx,
maybe_changed: bool,
}
impl<'a, T, Idx, K, const N: usize> FindMut<'a, T, Idx, K, N>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
{
fn pop_internal(&mut self) -> T {
if self.is_head {
unsafe { self.list.pop_unchecked() }
} else {
let prev = unsafe { self.prev_index.get_unchecked() };
let curr = unsafe { self.index.get_unchecked() };
self.list.node_at_mut(prev).next = self.list.node_at_mut(curr).next;
self.list.node_at_mut(curr).next = self.list.free;
self.list.free = self.index;
self.list.extract_data_in_node_at(curr)
}
}
#[inline]
pub fn pop(mut self) -> T {
self.pop_internal()
}
#[inline]
pub fn finish(self) {
drop(self)
}
}
impl<T, Idx, K, const N: usize> Drop for FindMut<'_, T, Idx, K, N>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
{
fn drop(&mut self) {
if self.maybe_changed {
let val = self.pop_internal();
unsafe { self.list.push_unchecked(val) };
}
}
}
impl<T, Idx, K, const N: usize> Deref for FindMut<'_, T, Idx, K, N>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.list
.read_data_in_node_at(unsafe { self.index.get_unchecked() })
}
}
impl<T, Idx, K, const N: usize> DerefMut for FindMut<'_, T, Idx, K, N>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.maybe_changed = true;
self.list
.read_mut_data_in_node_at(unsafe { self.index.get_unchecked() })
}
}
impl<T, Idx, K, const N: usize> fmt::Debug for SortedLinkedList<T, Idx, K, N>
where
T: Ord + core::fmt::Debug,
Idx: SortedLinkedListIndex,
K: Kind,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T, Idx, K, const N: usize> Drop for SortedLinkedList<T, Idx, K, N>
where
Idx: SortedLinkedListIndex,
{
fn drop(&mut self) {
let mut index = self.head;
while let Some(i) = index.option() {
let node = self.node_at_mut(i);
index = node.next;
unsafe {
ptr::drop_in_place(node.val.as_mut_ptr());
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn const_new() {
static mut _V1: SortedLinkedList<u32, LinkedIndexU8, Max, 100> = SortedLinkedList::new_u8();
static mut _V2: SortedLinkedList<u32, LinkedIndexU16, Max, 10_000> =
SortedLinkedList::new_u16();
static mut _V3: SortedLinkedList<u32, LinkedIndexUsize, Max, 100_000> =
SortedLinkedList::new_usize();
}
#[test]
fn test_peek() {
let mut ll: SortedLinkedList<u32, LinkedIndexUsize, Max, 3> = SortedLinkedList::new_usize();
ll.push(1).unwrap();
assert_eq!(ll.peek().unwrap(), &1);
ll.push(2).unwrap();
assert_eq!(ll.peek().unwrap(), &2);
ll.push(3).unwrap();
assert_eq!(ll.peek().unwrap(), &3);
let mut ll: SortedLinkedList<u32, LinkedIndexUsize, Min, 3> = SortedLinkedList::new_usize();
ll.push(2).unwrap();
assert_eq!(ll.peek().unwrap(), &2);
ll.push(1).unwrap();
assert_eq!(ll.peek().unwrap(), &1);
ll.push(3).unwrap();
assert_eq!(ll.peek().unwrap(), &1);
}
#[test]
fn test_full() {
let mut ll: SortedLinkedList<u32, LinkedIndexUsize, Max, 3> = SortedLinkedList::new_usize();
ll.push(1).unwrap();
ll.push(2).unwrap();
ll.push(3).unwrap();
assert!(ll.is_full())
}
#[test]
fn test_empty() {
let ll: SortedLinkedList<u32, LinkedIndexUsize, Max, 3> = SortedLinkedList::new_usize();
assert!(ll.is_empty())
}
#[test]
fn test_zero_size() {
let ll: SortedLinkedList<u32, LinkedIndexUsize, Max, 0> = SortedLinkedList::new_usize();
assert!(ll.is_empty());
assert!(ll.is_full());
}
#[test]
fn test_rejected_push() {
let mut ll: SortedLinkedList<u32, LinkedIndexUsize, Max, 3> = SortedLinkedList::new_usize();
ll.push(1).unwrap();
ll.push(2).unwrap();
ll.push(3).unwrap();
let r = ll.push(4);
assert_eq!(r, Err(4));
}
#[test]
fn test_updating() {
let mut ll: SortedLinkedList<u32, LinkedIndexUsize, Max, 3> = SortedLinkedList::new_usize();
ll.push(1).unwrap();
ll.push(2).unwrap();
ll.push(3).unwrap();
let mut find = ll.find_mut(|v| *v == 2).unwrap();
*find += 1000;
find.finish();
assert_eq!(ll.peek().unwrap(), &1002);
let mut find = ll.find_mut(|v| *v == 3).unwrap();
*find += 1000;
find.finish();
assert_eq!(ll.peek().unwrap(), &1003);
ll.find_mut(|v| *v == 1003).unwrap().pop();
assert_eq!(ll.peek().unwrap(), &1002);
}
#[test]
fn test_updating_1() {
let mut ll: SortedLinkedList<u32, LinkedIndexUsize, Max, 3> = SortedLinkedList::new_usize();
ll.push(1).unwrap();
let v = ll.pop().unwrap();
assert_eq!(v, 1);
}
#[test]
fn test_updating_2() {
let mut ll: SortedLinkedList<u32, LinkedIndexUsize, Max, 3> = SortedLinkedList::new_usize();
ll.push(1).unwrap();
let mut find = ll.find_mut(|v| *v == 1).unwrap();
*find += 1000;
find.finish();
assert_eq!(ll.peek().unwrap(), &1001);
}
}