cordyceps/sorted_list.rs
1//! [Intrusive], singly-linked, sorted, linked list.
2//!
3//! See the documentation for the [`SortedList`] and [`SortedListIter`] types for
4//! details.
5//!
6//! [Intrusive]: crate#intrusive-data-structures
7
8use crate::{Linked, Stack};
9use core::{
10 cmp::{Ord, Ordering},
11 fmt,
12 marker::PhantomData,
13 ptr::NonNull,
14};
15
16pub use crate::stack::Links;
17
18/// A sorted singly linked list
19///
20/// This behaves similar to [`Stack`], in that it is a singly linked list,
21/// however items are stored in an ordered fashion. This means that insertion
22/// is an _O_(_n_) operation, and retrieval of the first item is an _O_(1) operation.
23///
24/// It allows for a user selected ordering operation. If your type `T` implements
25/// [`Ord`]:
26///
27/// * Consider using [`SortedList::new_min()`] if you want **smallest** items sorted first.
28/// * Consider using [`SortedList::new_max()`] if you want **largest** items sorted first.
29///
30/// If your type `T` does NOT implement [`Ord`], or you want to use
31/// a custom sorting anyway, consider using [`SortedList::new_with_cmp()`]
32///
33/// In order to be part of a `SortedList`, a type `T` must implement
34/// the [`Linked`] trait for [`sorted_list::Links<T>`](Links), which is an alias for
35/// [`stack::Links<T>`](Links). This means that you can link the same element into
36/// either structure, but you can't have something that's linked into a `SortedList`
37/// and a `Stack` at the same time (without wrapper structs that have separate sets
38/// of links, left as an exercise for the reader).
39///
40/// Pushing elements into a `SortedList` takes ownership of those elements
41/// through an owning [`Handle` type](Linked::Handle). Dropping a
42/// `SortedList` drops all elements currently linked into the stack.
43pub struct SortedList<T: Linked<Links<T>>> {
44 head: Option<NonNull<T>>,
45 // Returns if LHS is less/same/greater than RHS
46 func: fn(&T, &T) -> Ordering,
47}
48
49#[inline]
50fn invert_sort<T: Ord>(a: &T, b: &T) -> Ordering {
51 // Inverted sort order!
52 T::cmp(b, a)
53}
54
55impl<T> SortedList<T>
56where
57 T: Linked<Links<T>>,
58 T: Ord,
59{
60 /// Create a new (empty) sorted list, sorted LEAST FIRST
61 ///
62 /// * Consider using [`SortedList::new_max()`] if you want **largest** items sorted first.
63 /// * Consider using [`SortedList::new_with_cmp()`] if you want to provide your own sorting
64 /// implementation.
65 ///
66 /// If two items are considered of equal value, new values will be placed AFTER
67 /// old values.
68 #[must_use]
69 pub const fn new_min() -> Self {
70 Self::new_with_cmp(T::cmp)
71 }
72
73 /// Create a new sorted list, consuming the stack, sorted LEAST FIRST
74 #[must_use]
75 pub fn from_stack_min(stack: Stack<T>) -> Self {
76 Self::from_stack_with_cmp(stack, T::cmp)
77 }
78
79 /// Create a new (empty) sorted list, sorted GREATEST FIRST
80 ///
81 /// * Consider using [`SortedList::new_min()`] if you want **smallest** items sorted first.
82 /// * Consider using [`SortedList::new_with_cmp()`] if you want to provide your own sorting
83 /// implementation.
84 ///
85 /// If two items are considered of equal value, new values will be placed AFTER
86 /// old values.
87 #[must_use]
88 pub const fn new_max() -> Self {
89 Self::new_with_cmp(invert_sort::<T>)
90 }
91
92 /// Create a new sorted list, consuming the stack, sorted GREATEST FIRST
93 #[must_use]
94 pub fn from_stack_max(stack: Stack<T>) -> Self {
95 Self::from_stack_with_cmp(stack, invert_sort::<T>)
96 }
97}
98
99impl<T: Linked<Links<T>>> SortedList<T> {
100 /// Create a new (empty) sorted list with the given ordering function
101 ///
102 /// If your type T implements [`Ord`]:
103 ///
104 /// * Consider using [`SortedList::new_min()`] if you want **smallest** items sorted first.
105 /// * Consider using [`SortedList::new_max()`] if you want **largest** items sorted first.
106 ///
107 /// If `T` contained an `i32`, and you wanted the SMALLEST items at the
108 /// front, then you could provide a function something like:
109 ///
110 /// ```rust
111 /// let f: fn(&i32, &i32) -> core::cmp::Ordering = |lhs, rhs| {
112 /// lhs.cmp(rhs)
113 /// };
114 /// ```
115 ///
116 /// SortedList takes a function (and not just [Ord]) so you can use it on types
117 /// that don't have a general way of ordering them, allowing you to select a
118 /// specific metric within the sorting function.
119 ///
120 /// If two items are considered of equal value, new values will be placed AFTER
121 /// old values.
122 pub const fn new_with_cmp(f: fn(&T, &T) -> Ordering) -> Self {
123 Self {
124 func: f,
125 head: None,
126 }
127 }
128
129 /// Create a new sorted list, consuming the stack, using the provided ordering function
130 pub fn from_stack_with_cmp(stack: Stack<T>, f: fn(&T, &T) -> Ordering) -> Self {
131 let mut slist = Self::new_with_cmp(f);
132 slist.extend(stack);
133 slist
134 }
135
136 /// Pop the front-most item from the list, returning it by ownership (if it exists)
137 ///
138 /// Note that "front" here refers to the sorted ordering. If this list was created
139 /// with [`SortedList::new_min`], the SMALLEST item will be popped. If this was
140 /// created with [`SortedList::new_max`], the LARGEST item will be popped.
141 ///
142 /// This is an _O_(1) operation.
143 #[must_use]
144 pub fn pop_front(&mut self) -> Option<T::Handle> {
145 test_trace!(?self.head, "SortedList::pop_front");
146 let head = self.head.take()?;
147 unsafe {
148 // Safety: we have exclusive ownership over this chunk of stack.
149
150 // advance the head link to the next node after the current one (if
151 // there is one).
152 self.head = T::links(head).as_mut().next.with_mut(|next| (*next).take());
153
154 test_trace!(?self.head, "SortedList::pop -> popped");
155
156 // return the current node
157 Some(T::from_ptr(head))
158 }
159 }
160
161 /// Insert a single item into the list, in its sorted order position
162 ///
163 /// Note that if the inserted item is [`Equal`](Ordering::Equal) to another
164 /// item in the list, the newest item is always sorted AFTER the existing
165 /// item.
166 ///
167 /// This is an _O_(_n_) operation.
168 pub fn insert(&mut self, element: T::Handle) {
169 let eptr = T::into_ptr(element);
170 test_trace!(?eptr, ?self.head, "SortedList::insert");
171 debug_assert!(
172 unsafe { T::links(eptr).as_ref().next.with(|n| (*n).is_none()) },
173 "Inserted items should not already be part of a list"
174 );
175
176 // Take a long-lived reference to the new element
177 let eref = unsafe { eptr.as_ref() };
178
179 // Special case for empty head
180 //
181 // If the head is null, then just place the item
182 let Some(mut cursor) = self.head else {
183 self.head = Some(eptr);
184 return;
185 };
186
187 // Special case for head: do we replace current head with new element?
188 {
189 // compare, but make sure we drop the live reference to the cursor
190 // so to be extra sure about NOT violating provenance, when we
191 // potentially mutate the cursor below, and we really don't want
192 // a shared reference to be live.
193 let cmp = {
194 let cref = unsafe { cursor.as_ref() };
195 (self.func)(cref, eref)
196 };
197
198 // If cursor node is LESS or EQUAL: keep moving.
199 // If cursor node is GREATER: we need to place the new item BEFORE
200 if cmp == Ordering::Greater {
201 unsafe {
202 let links = T::links(eptr).as_mut();
203 links.next.with_mut(|next| {
204 *next = self.head.replace(eptr);
205 });
206 return;
207 }
208 }
209 }
210
211 // On every iteration of the loop, we know that the new element should
212 // be placed AFTER the current value of `cursor`, meaning that we need
213 // to decide whether we:
214 //
215 // * just append (if next is null)
216 // * insert between cursor and cursor.next (if elem is < c.next)
217 // * just iterate (if elem >= c.next)
218 loop {
219 // Safety: We have exclusive access to the list, we are allowed to
220 // access and mutate it (carefully)
221 unsafe {
222 // Get the cursor's links
223 let clinks = T::links(cursor).as_mut();
224 // Peek into the cursor's next item
225 let next = clinks.next.with_mut(|next| {
226 // We can take a reference here, as we have exclusive access
227 let mutref = &mut *next;
228
229 if let Some(n) = mutref {
230 // If next is some, store this pointer
231 let nptr: NonNull<T> = *n;
232 // Then compare the next element with the new element
233 let cmp = {
234 let nref: &T = nptr.as_ref();
235 (self.func)(nref, eref)
236 };
237
238 if cmp == Ordering::Greater {
239 // As above, if cursor.next > element, then we
240 // need to insert between cursor and next.
241 //
242 // First, get the current element's links...
243 let elinks = T::links(eptr).as_mut();
244 // ...then store cursor.next.next in element.next,
245 // and store element in cursor.next.
246 elinks.next.with_mut(|enext| {
247 *enext = mutref.replace(eptr);
248 });
249 // If we have placed element, there is no next value
250 // for cursor.
251 None
252 } else {
253 // If cursor.next <= element, then we just need to
254 // iterate, so return the NonNull that represents
255 // cursor.next, so we can move cursor there.
256 Some(nptr)
257 }
258 } else {
259 // "just append" case - assign element to cursor.next
260 *mutref = Some(eptr);
261 // If we have placed element, there is no next value
262 // for cursor
263 None
264 }
265 });
266
267 // We do the assignment through this tricky return to ensure that the
268 // mutable reference to cursor.next we held as "mutref" above has been
269 // dropped, so we are not mutating `cursor` while a reference derived
270 // from it's provenance is live.
271 //
272 // We also can't early return inside the loop because all of the body
273 // is inside a closure.
274 //
275 // This might be overly cautious, refactor carefully (with miri).
276 let Some(n) = next else {
277 // We're done, return
278 return;
279 };
280 cursor = n;
281 }
282 }
283 }
284
285 /// Iterate through the items of the list, in sorted order
286 pub fn iter(&self) -> SortedListIter<'_, T> {
287 SortedListIter {
288 _plt: PhantomData,
289 node: self.head,
290 }
291 }
292}
293
294impl<T: Linked<Links<T>>> Extend<T::Handle> for SortedList<T> {
295 fn extend<I: IntoIterator<Item = T::Handle>>(&mut self, iter: I) {
296 for elem in iter {
297 self.insert(elem);
298 }
299 }
300}
301
302impl<T> fmt::Debug for SortedList<T>
303where
304 T: Linked<Links<T>>,
305{
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 let Self { head, func: _ } = self;
308 f.debug_struct("SortedList").field("head", head).finish()
309 }
310}
311
312impl<T: Linked<Links<T>>> Drop for SortedList<T> {
313 fn drop(&mut self) {
314 // We just turn the list into a stack then run the stack drop code.
315 // It already has correct + tested logic for dropping a singly
316 // linked list of items one at a time.
317 let stack = Stack {
318 head: self.head.take(),
319 };
320 drop(stack);
321 }
322}
323
324/// A borrowing iterator of a [`SortedList`]
325pub struct SortedListIter<'a, T: Linked<Links<T>>> {
326 _plt: PhantomData<&'a SortedList<T>>,
327 node: Option<NonNull<T>>,
328}
329
330impl<'a, T: Linked<Links<T>>> Iterator for SortedListIter<'a, T> {
331 type Item = &'a T;
332
333 fn next(&mut self) -> Option<Self::Item> {
334 let nn = self.node.take()?;
335 unsafe {
336 // Advance our pointer to next
337 let links = T::links(nn).as_ref();
338 self.node = links.next.with(|t| *t);
339 Some(nn.as_ref())
340 }
341 }
342}
343
344#[cfg(test)]
345mod loom {
346 use super::*;
347 use crate::loom;
348 use crate::stack::test_util::Entry;
349
350 #[test]
351 fn builtin_sort_min() {
352 loom::model(|| {
353 let mut slist = SortedList::<Entry>::new_min();
354 // Insert out of order
355 slist.insert(Entry::new(20));
356 slist.insert(Entry::new(10));
357 slist.insert(Entry::new(30));
358 slist.insert(Entry::new(25));
359 slist.insert(Entry::new(35));
360 slist.insert(Entry::new(1));
361 slist.insert(Entry::new(2));
362 slist.insert(Entry::new(3));
363 // expected is in order
364 let expected = [1, 2, 3, 10, 20, 25, 30, 35];
365
366 // Does iteration work (twice)?
367 {
368 let mut ct = 0;
369 let siter = slist.iter();
370 for (l, r) in expected.iter().zip(siter) {
371 ct += 1;
372 assert_eq!(*l, r.val);
373 }
374 assert_eq!(ct, expected.len());
375 }
376 {
377 let mut ct = 0;
378 let siter = slist.iter();
379 for (l, r) in expected.iter().zip(siter) {
380 ct += 1;
381 assert_eq!(*l, r.val);
382 }
383 assert_eq!(ct, expected.len());
384 }
385
386 // Does draining work (once)?
387 {
388 let mut ct = 0;
389 for exp in expected.iter() {
390 let act = slist.pop_front().unwrap();
391 ct += 1;
392 assert_eq!(*exp, act.val);
393 }
394 assert_eq!(ct, expected.len());
395 assert!(slist.pop_front().is_none());
396 }
397 })
398 }
399
400 #[test]
401 fn builtin_sort_max() {
402 loom::model(|| {
403 let mut slist = SortedList::<Entry>::new_max();
404 // Insert out of order
405 slist.insert(Entry::new(20));
406 slist.insert(Entry::new(10));
407 slist.insert(Entry::new(30));
408 slist.insert(Entry::new(25));
409 slist.insert(Entry::new(35));
410 slist.insert(Entry::new(1));
411 slist.insert(Entry::new(2));
412 slist.insert(Entry::new(3));
413 // expected is in order (reverse!)
414 let expected = [35, 30, 25, 20, 10, 3, 2, 1];
415
416 // Does iteration work (twice)?
417 {
418 let mut ct = 0;
419 let siter = slist.iter();
420 for (l, r) in expected.iter().zip(siter) {
421 ct += 1;
422 assert_eq!(*l, r.val);
423 }
424 assert_eq!(ct, expected.len());
425 }
426 {
427 let mut ct = 0;
428 let siter = slist.iter();
429 for (l, r) in expected.iter().zip(siter) {
430 ct += 1;
431 assert_eq!(*l, r.val);
432 }
433 assert_eq!(ct, expected.len());
434 }
435
436 // Does draining work (once)?
437 {
438 let mut ct = 0;
439 for exp in expected.iter() {
440 let act = slist.pop_front().unwrap();
441 ct += 1;
442 assert_eq!(*exp, act.val);
443 }
444 assert_eq!(ct, expected.len());
445 assert!(slist.pop_front().is_none());
446 }
447 })
448 }
449
450 #[test]
451 fn slist_basic() {
452 loom::model(|| {
453 let mut slist = SortedList::<Entry>::new_with_cmp(|lhs, rhs| lhs.val.cmp(&rhs.val));
454 // Insert out of order
455 slist.insert(Entry::new(20));
456 slist.insert(Entry::new(10));
457 slist.insert(Entry::new(30));
458 slist.insert(Entry::new(25));
459 slist.insert(Entry::new(35));
460 slist.insert(Entry::new(1));
461 slist.insert(Entry::new(2));
462 slist.insert(Entry::new(3));
463 // expected is in order
464 let expected = [1, 2, 3, 10, 20, 25, 30, 35];
465
466 // Does iteration work (twice)?
467 {
468 let mut ct = 0;
469 let siter = slist.iter();
470 for (l, r) in expected.iter().zip(siter) {
471 ct += 1;
472 assert_eq!(*l, r.val);
473 }
474 assert_eq!(ct, expected.len());
475 }
476 {
477 let mut ct = 0;
478 let siter = slist.iter();
479 for (l, r) in expected.iter().zip(siter) {
480 ct += 1;
481 assert_eq!(*l, r.val);
482 }
483 assert_eq!(ct, expected.len());
484 }
485
486 // Does draining work (once)?
487 {
488 let mut ct = 0;
489 for exp in expected.iter() {
490 let act = slist.pop_front().unwrap();
491 ct += 1;
492 assert_eq!(*exp, act.val);
493 }
494 assert_eq!(ct, expected.len());
495 assert!(slist.pop_front().is_none());
496 }
497
498 // Do a little pop and remove dance to make sure we correctly unset
499 // next on popped items (there is a debug assert for this)
500 slist.insert(Entry::new(20));
501 slist.insert(Entry::new(10));
502 slist.insert(Entry::new(30));
503 let x = slist.pop_front().unwrap();
504 slist.insert(x);
505 let y = slist.pop_front().unwrap();
506 let z = slist.pop_front().unwrap();
507 slist.insert(y);
508 slist.insert(z);
509 })
510 }
511}