Skip to main content

rustpython_common/
linked_list.rs

1// spell-checker:disable
2
3//! This module is modified from tokio::util::linked_list: <https://github.com/tokio-rs/tokio/blob/master/tokio/src/util/linked_list.rs>
4//! Tokio is licensed under the MIT license:
5//!
6//! Copyright (c) 2021 Tokio Contributors
7//!
8//! Permission is hereby granted, free of charge, to any
9//! person obtaining a copy of this software and associated
10//! documentation files (the "Software"), to deal in the
11//! Software without restriction, including without
12//! limitation the rights to use, copy, modify, merge,
13//! publish, distribute, sublicense, and/or sell copies of
14//! the Software, and to permit persons to whom the Software
15//! is furnished to do so, subject to the following
16//! conditions:
17//!
18//! The above copyright notice and this permission notice
19//! shall be included in all copies or substantial portions
20//! of the Software.
21//!
22//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
23//! ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
24//! TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
25//! PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
26//! SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27//! CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28//! OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
29//! IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30//! DEALINGS IN THE SOFTWARE.
31//!
32//! Original header:
33//!
34//! An intrusive double linked list of data.
35//!
36//! The data structure supports tracking pinned nodes. Most of the data
37//! structure's APIs are `unsafe` as they require the caller to ensure the
38//! specified node is actually contained by the list.
39
40#![allow(clippy::new_without_default, clippy::missing_safety_doc)]
41
42use core::cell::UnsafeCell;
43use core::fmt;
44use core::marker::{PhantomData, PhantomPinned};
45use core::mem::ManuallyDrop;
46use core::ptr::{self, NonNull};
47
48/// An intrusive linked list.
49///
50/// Currently, the list is not emptied on drop. It is the caller's
51/// responsibility to ensure the list is empty before dropping it.
52pub struct LinkedList<L, T> {
53    /// Linked list head
54    head: Option<NonNull<T>>,
55
56    // /// Linked list tail
57    // tail: Option<NonNull<T>>,
58    /// Node type marker.
59    _marker: PhantomData<*const L>,
60}
61
62unsafe impl<L: Link> Send for LinkedList<L, L::Target> where L::Target: Send {}
63unsafe impl<L: Link> Sync for LinkedList<L, L::Target> where L::Target: Sync {}
64
65/// Defines how a type is tracked within a linked list.
66///
67/// In order to support storing a single type within multiple lists, accessing
68/// the list pointers is decoupled from the entry type.
69///
70/// # Safety
71///
72/// Implementations must guarantee that `Target` types are pinned in memory. In
73/// other words, when a node is inserted, the value will not be moved as long as
74/// it is stored in the list.
75pub unsafe trait Link {
76    /// Handle to the list entry.
77    ///
78    /// This is usually a pointer-ish type.
79    type Handle;
80
81    /// Node type.
82    type Target;
83
84    /// Convert the handle to a raw pointer without consuming the handle.
85    #[allow(clippy::wrong_self_convention)]
86    fn as_raw(handle: &Self::Handle) -> NonNull<Self::Target>;
87
88    /// Convert the raw pointer to a handle
89    unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self::Handle;
90
91    /// Return the pointers for a node
92    unsafe fn pointers(target: NonNull<Self::Target>) -> NonNull<Pointers<Self::Target>>;
93}
94
95/// Previous / next pointers.
96pub struct Pointers<T> {
97    inner: UnsafeCell<PointersInner<T>>,
98}
99/// We do not want the compiler to put the `noalias` attribute on mutable
100/// references to this type, so the type has been made `!Unpin` with a
101/// `PhantomPinned` field.
102///
103/// Additionally, we never access the `prev` or `next` fields directly, as any
104/// such access would implicitly involve the creation of a reference to the
105/// field, which we want to avoid since the fields are not `!Unpin`, and would
106/// hence be given the `noalias` attribute if we were to do such an access.
107/// As an alternative to accessing the fields directly, the `Pointers` type
108/// provides getters and setters for the two fields, and those are implemented
109/// using raw pointer casts and offsets, which is valid since the struct is
110/// #[repr(C)].
111///
112/// See this link for more information:
113/// <https://github.com/rust-lang/rust/pull/82834>
114#[repr(C)]
115struct PointersInner<T> {
116    /// The previous node in the list. null if there is no previous node.
117    ///
118    /// This field is accessed through pointer manipulation, so it is not dead code.
119    #[allow(dead_code)]
120    prev: Option<NonNull<T>>,
121
122    /// The next node in the list. null if there is no previous node.
123    ///
124    /// This field is accessed through pointer manipulation, so it is not dead code.
125    #[allow(dead_code)]
126    next: Option<NonNull<T>>,
127
128    /// This type is !Unpin due to the heuristic from:
129    /// <https://github.com/rust-lang/rust/pull/82834>
130    _pin: PhantomPinned,
131}
132
133unsafe impl<T: Send> Send for PointersInner<T> {}
134unsafe impl<T: Sync> Sync for PointersInner<T> {}
135
136unsafe impl<T: Send> Send for Pointers<T> {}
137unsafe impl<T: Sync> Sync for Pointers<T> {}
138
139// ===== impl LinkedList =====
140
141impl<L, T> LinkedList<L, T> {
142    /// Creates an empty linked list.
143    pub const fn new() -> Self {
144        Self {
145            head: None,
146            // tail: None,
147            _marker: PhantomData,
148        }
149    }
150}
151
152impl<L: Link> LinkedList<L, L::Target> {
153    /// Adds an element first in the list.
154    pub fn push_front(&mut self, val: L::Handle) {
155        // The value should not be dropped, it is being inserted into the list
156        let val = ManuallyDrop::new(val);
157        let ptr = L::as_raw(&val);
158        assert_ne!(self.head, Some(ptr));
159        unsafe {
160            // Verify the node is not already in a list (pointers must be clean)
161            debug_assert!(
162                L::pointers(ptr).as_ref().get_prev().is_none(),
163                "push_front: node already has prev pointer (double-insert?)"
164            );
165            debug_assert!(
166                L::pointers(ptr).as_ref().get_next().is_none(),
167                "push_front: node already has next pointer (double-insert?)"
168            );
169            L::pointers(ptr).as_mut().set_next(self.head);
170            L::pointers(ptr).as_mut().set_prev(None);
171
172            if let Some(head) = self.head {
173                L::pointers(head).as_mut().set_prev(Some(ptr));
174            }
175
176            self.head = Some(ptr);
177
178            // if self.tail.is_none() {
179            //     self.tail = Some(ptr);
180            // }
181        }
182    }
183
184    // /// Removes the last element from a list and returns it, or None if it is
185    // /// empty.
186    // pub fn pop_back(&mut self) -> Option<L::Handle> {
187    //     unsafe {
188    //         let last = self.tail?;
189    //         self.tail = L::pointers(last).as_ref().get_prev();
190
191    //         if let Some(prev) = L::pointers(last).as_ref().get_prev() {
192    //             L::pointers(prev).as_mut().set_next(None);
193    //         } else {
194    //             self.head = None
195    //         }
196
197    //         L::pointers(last).as_mut().set_prev(None);
198    //         L::pointers(last).as_mut().set_next(None);
199
200    //         Some(L::from_raw(last))
201    //     }
202    // }
203
204    /// Removes the first element from the list and returns it, or None if empty.
205    pub fn pop_front(&mut self) -> Option<L::Handle> {
206        let head = self.head?;
207        unsafe {
208            self.head = L::pointers(head).as_ref().get_next();
209            if let Some(new_head) = self.head {
210                L::pointers(new_head).as_mut().set_prev(None);
211            }
212            L::pointers(head).as_mut().set_next(None);
213            L::pointers(head).as_mut().set_prev(None);
214            Some(L::from_raw(head))
215        }
216    }
217
218    /// Returns whether the linked list does not contain any node
219    pub const fn is_empty(&self) -> bool {
220        self.head.is_none()
221        // if self.head.is_some() {
222        //     return false;
223        // }
224
225        // assert!(self.tail.is_none());
226        // true
227    }
228
229    /// Removes the specified node from the list
230    ///
231    /// # Safety
232    ///
233    /// The caller **must** ensure that `node` is currently contained by
234    /// `self` or not contained by any other list.
235    pub unsafe fn remove(&mut self, node: NonNull<L::Target>) -> Option<L::Handle> {
236        unsafe {
237            if let Some(prev) = L::pointers(node).as_ref().get_prev() {
238                debug_assert_eq!(
239                    L::pointers(prev).as_ref().get_next(),
240                    Some(node),
241                    "linked list corruption: prev->next != node (prev={prev:p}, node={node:p})"
242                );
243                L::pointers(prev)
244                    .as_mut()
245                    .set_next(L::pointers(node).as_ref().get_next());
246            } else {
247                if self.head != Some(node) {
248                    return None;
249                }
250
251                self.head = L::pointers(node).as_ref().get_next();
252            }
253
254            if let Some(next) = L::pointers(node).as_ref().get_next() {
255                debug_assert_eq!(
256                    L::pointers(next).as_ref().get_prev(),
257                    Some(node),
258                    "linked list corruption: next->prev != node (next={next:p}, node={node:p})"
259                );
260                L::pointers(next)
261                    .as_mut()
262                    .set_prev(L::pointers(node).as_ref().get_prev());
263            } else {
264                // // This might be the last item in the list
265                // if self.tail != Some(node) {
266                //     return None;
267                // }
268
269                // self.tail = L::pointers(node).as_ref().get_prev();
270            }
271
272            L::pointers(node).as_mut().set_next(None);
273            L::pointers(node).as_mut().set_prev(None);
274
275            Some(L::from_raw(node))
276        }
277    }
278
279    // pub fn last(&self) -> Option<&L::Target> {
280    //     let tail = self.tail.as_ref()?;
281    //     unsafe { Some(&*tail.as_ptr()) }
282    // }
283
284    // === rustpython additions ===
285
286    pub fn iter(&self) -> impl Iterator<Item = &L::Target> {
287        core::iter::successors(self.head, |node| unsafe {
288            L::pointers(*node).as_ref().get_next()
289        })
290        .map(|ptr| unsafe { ptr.as_ref() })
291    }
292}
293
294impl<L: Link> fmt::Debug for LinkedList<L, L::Target> {
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        f.debug_struct("LinkedList")
297            .field("head", &self.head)
298            // .field("tail", &self.tail)
299            .finish()
300    }
301}
302
303impl<L: Link> Default for LinkedList<L, L::Target> {
304    fn default() -> Self {
305        Self::new()
306    }
307}
308
309// ===== impl DrainFilter =====
310
311pub struct DrainFilter<'a, T: Link, F> {
312    list: &'a mut LinkedList<T, T::Target>,
313    filter: F,
314    curr: Option<NonNull<T::Target>>,
315}
316
317impl<T: Link> LinkedList<T, T::Target> {
318    pub const fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F>
319    where
320        F: FnMut(&mut T::Target) -> bool,
321    {
322        let curr = self.head;
323        DrainFilter {
324            curr,
325            filter,
326            list: self,
327        }
328    }
329}
330
331impl<T, F> Iterator for DrainFilter<'_, T, F>
332where
333    T: Link,
334    F: FnMut(&mut T::Target) -> bool,
335{
336    type Item = T::Handle;
337
338    fn next(&mut self) -> Option<Self::Item> {
339        while let Some(curr) = self.curr {
340            // safety: the pointer references data contained by the list
341            self.curr = unsafe { T::pointers(curr).as_ref() }.get_next();
342
343            // safety: the value is still owned by the linked list.
344            if (self.filter)(unsafe { &mut *curr.as_ptr() }) {
345                return unsafe { self.list.remove(curr) };
346            }
347        }
348
349        None
350    }
351}
352
353// ===== impl Pointers =====
354
355impl<T> Pointers<T> {
356    /// Create a new set of empty pointers
357    pub const fn new() -> Self {
358        Self {
359            inner: UnsafeCell::new(PointersInner {
360                prev: None,
361                next: None,
362                _pin: PhantomPinned,
363            }),
364        }
365    }
366
367    pub const fn get_prev(&self) -> Option<NonNull<T>> {
368        // SAFETY: prev is the first field in PointersInner, which is #[repr(C)].
369        unsafe {
370            let inner = self.inner.get();
371            let prev = inner as *const Option<NonNull<T>>;
372            ptr::read(prev)
373        }
374    }
375    pub const fn get_next(&self) -> Option<NonNull<T>> {
376        // SAFETY: next is the second field in PointersInner, which is #[repr(C)].
377        unsafe {
378            let inner = self.inner.get();
379            let prev = inner as *const Option<NonNull<T>>;
380            let next = prev.add(1);
381            ptr::read(next)
382        }
383    }
384
385    pub const fn set_prev(&mut self, value: Option<NonNull<T>>) {
386        // SAFETY: prev is the first field in PointersInner, which is #[repr(C)].
387        unsafe {
388            let inner = self.inner.get();
389            let prev = inner as *mut Option<NonNull<T>>;
390            ptr::write(prev, value);
391        }
392    }
393    pub const fn set_next(&mut self, value: Option<NonNull<T>>) {
394        // SAFETY: next is the second field in PointersInner, which is #[repr(C)].
395        unsafe {
396            let inner = self.inner.get();
397            let prev = inner as *mut Option<NonNull<T>>;
398            let next = prev.add(1);
399            ptr::write(next, value);
400        }
401    }
402}
403
404impl<T> fmt::Debug for Pointers<T> {
405    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406        let prev = self.get_prev();
407        let next = self.get_next();
408        f.debug_struct("Pointers")
409            .field("prev", &prev)
410            .field("next", &next)
411            .finish()
412    }
413}