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}