1//! Sorted Linked List
2
3use std::{cell::Cell, cmp::Ordering, ptr};
4
5use crate::utility_types::Delta;
6pub(crate) unsafe trait Elem {
7 fn prev(&self) -> &Cell<*const Self>;
8 fn next(&self) -> &Cell<*const Self>;
9 fn key(&self) -> &Cell<u32>;
10}
11
12pub(crate) enum AddToSllResult<'a, E: Elem> {
13 NoHead,
14 EmptyHead(&'a Cell<*const E>),
15 SmallerThanHead(&'a Cell<*const E>),
16 SmallerThanNotHead(*const E),
17 AlreadyInSll(*const E),
18}
19
20impl<'a, E: Elem> AddToSllResult<'a, E> {
21 pub(crate) fn add_to_sll(&self, elem_ptr: *const E) {
22 unsafe {
23 (*elem_ptr).prev().set(elem_ptr);
24 (*elem_ptr).next().set(elem_ptr);
25
26 match self {
27 // Case 1: empty head, replace it.
28 AddToSllResult::EmptyHead(head) => head.set(elem_ptr),
29
30 // Case 2: we are smaller than the head, replace it.
31 AddToSllResult::SmallerThanHead(head) => {
32 let old_head = head.get();
33 let prev = (*old_head).prev().replace(elem_ptr);
34 (*prev).next().set(elem_ptr);
35 (*elem_ptr).next().set(old_head);
36 (*elem_ptr).prev().set(prev);
37 head.set(elem_ptr);
38 }
39
40 // Case 3: insert in place found by looping
41 AddToSllResult::SmallerThanNotHead(curr) => {
42 let next = (**curr).next().replace(elem_ptr);
43 (*next).prev().set(elem_ptr);
44 (*elem_ptr).prev().set(*curr);
45 (*elem_ptr).next().set(next);
46 }
47 AddToSllResult::NoHead | AddToSllResult::AlreadyInSll(_) => (),
48 }
49 }
50 }
51}
52
53#[cold]
54pub(crate) fn init<'a, E: Elem>(
55 head: Option<&'a Cell<*const E>>,
56 elem: &E,
57) -> AddToSllResult<'a, E> {
58 if let Some(head: &Cell<*const E>) = head {
59 link(head, elem)
60 } else {
61 AddToSllResult::NoHead
62 }
63}
64
65#[cold]
66pub(crate) fn unlink<E: Elem>(head: &Cell<*const E>, elem: &E) {
67 debug_assert!(!head.get().is_null(), "invalid linked list head");
68
69 let elem_ptr: *const E = elem;
70
71 let prev: *const E = elem.prev().replace(val:elem_ptr);
72 let next: *const E = elem.next().replace(val:elem_ptr);
73 unsafe {
74 debug_assert_eq!((*prev).next().get(), elem_ptr, "invalid linked list links");
75 debug_assert_eq!((*next).prev().get(), elem_ptr, "invalid linked list links");
76 (*prev).next().set(val:next);
77 (*next).prev().set(val:prev);
78 }
79
80 if head.get() == elem_ptr {
81 head.set(val:if next == elem_ptr { ptr::null() } else { next })
82 }
83}
84
85#[cold]
86pub(crate) fn link<'a, E: Elem>(head: &'a Cell<*const E>, elem: &E) -> AddToSllResult<'a, E> {
87 unsafe {
88 let old_head = head.get();
89 // Case 1: empty head, replace it.
90 if old_head.is_null() {
91 return AddToSllResult::EmptyHead(head);
92 }
93
94 // Case 2: we are smaller than the head, replace it.
95 if elem.key() < (*old_head).key() {
96 return AddToSllResult::SmallerThanHead(head);
97 }
98
99 // Case 3: loop *backward* until we find insertion place. Because of
100 // Case 2, we can't loop beyond the head.
101 let mut curr = (*old_head).prev().get();
102 loop {
103 match (*curr).key().cmp(elem.key()) {
104 Ordering::Less => return AddToSllResult::SmallerThanNotHead(curr),
105 Ordering::Equal => return AddToSllResult::AlreadyInSll(curr),
106 Ordering::Greater => curr = (*curr).prev().get(),
107 }
108 }
109 }
110}
111
112pub(crate) fn adjust<E: Elem>(elem: &E, from: u32, by: Delta<u32>) {
113 let elem_ptr: *const E = elem;
114
115 unsafe {
116 let mut curr: *const E = elem_ptr;
117 loop {
118 let mut key: u32 = (*curr).key().get();
119 if key >= from {
120 key += by;
121 (*curr).key().set(val:key);
122 }
123 curr = (*curr).next().get();
124 if curr == elem_ptr {
125 break;
126 }
127 }
128 }
129}
130