Skip to content

Commit 2b0614a

Browse files
amanjeevhawkw
authored andcommitted
feat(intruder_alarm::singly): add intrusive singly-linked list (#35)
* feat: adds skeleton files to singly mod, copied from doubly * chore: updates gitignore with alarm.iml * feat(singly): Playing around with some Rust features. Successfully failed a few tests. * feat(singly): removes references to prev * feat(single): removes not needed features for now * test(single): removes not needed tests, prev/back. * feat(singly): updates to Linked to return just Link, instead of Links struct * test(singly): updates some tests * feat(singly): removes Links struct and its impl * feat(singly): removes extraneous match pattern code * test(singly): removes extraneous test code * feat(singly): removes extraneous code; refactors name links to name next * feat(singly): refactors names to push and pop, given singly list is mainly used as a stack. * docs(singly): updates docstring * test(singly): removes commented code * chore(singly): removed a comment about adding Drop trait. * refactor(singly): PR review changes #35 Closes #8
1 parent 41a3b9d commit 2b0614a

File tree

4 files changed

+442
-0
lines changed

4 files changed

+442
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,4 @@ tasks.json
175175

176176
## ignore whole .idea
177177
.idea/*
178+
alarm.iml

intruder_alarm/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ use core::ptr::NonNull;
6060
pub mod cursor;
6161
pub use self::cursor::{Cursor, CursorMut};
6262
pub mod doubly;
63+
pub mod singly;
6364

6465
/// Trait for references which own their referent.
6566
///

intruder_alarm/src/singly/mod.rs

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
//! An intrusive linked list implementation using `RawLink`s modified as singly.
2+
//!
3+
//! An _intrusive_ list is a list structure wherein the type of element stored
4+
//! in the list holds references to other nodes. This means that we don't have
5+
//! to store a separate node data type that holds the stored elements and
6+
//! pointers to other nodes, reducing the amount of memory allocated. We can
7+
//! use intrusive lists in code that runs without the kernel memory allocator,
8+
//! like the allocator implementation itself, since each list element manages
9+
//! its own memory.
10+
use super::{Link, OwningRef};
11+
use core::marker::PhantomData;
12+
use core::mem;
13+
use core::ops::DerefMut;
14+
#[cfg(test)]
15+
mod tests;
16+
17+
//-----------------------------------------------------------------------------
18+
// Public API types
19+
//-----------------------------------------------------------------------------
20+
// List
21+
/// An intrusive singly-linked list.
22+
///
23+
/// This type is a wrapper around a series of [`Node`]s. It stores [`Link`]s
24+
/// to the head [`Node`]s and the length of the list.
25+
///
26+
/// # Type parameters
27+
/// - `T`: the type of the items stored by each `N`
28+
/// - `N`: the type of nodes in the list
29+
/// - `R`: the type of [`OwningRef`] that owns each `N`.
30+
///
31+
/// [`Node`]: trait.Node.html
32+
/// [`Link`]: ../struct.Link.html
33+
/// [`OwningRef]: ../trait.OwningRef.html
34+
#[derive(Default)]
35+
pub struct List<T, N, R> {
36+
/// Link to the head node of the list.
37+
head: Link<N>,
38+
39+
/// Length of the list.
40+
len: usize,
41+
42+
/// Type marker for items stored in the list.
43+
_elem_ty: PhantomData<T>,
44+
45+
/// Type marker for the `OwningRef` type.
46+
_ref_ty: PhantomData<R>,
47+
}
48+
49+
// Linked
50+
/// Trait that must be implemented in order to be a member of an intrusive
51+
/// singly linked list.
52+
pub trait Linked: Sized {
53+
/// Borrow this element's next [`Link`].
54+
///
55+
/// [`Links`]: struct.Link.html
56+
fn next(&self) -> &Link<Self>;
57+
58+
/// Mutably borrow this element's next [`Link`].
59+
///
60+
/// [`Links`]: struct.Link.html
61+
fn next_mut(&mut self) -> &mut Link<Self>;
62+
63+
/// De-link this node, returning its' next Link.
64+
fn take_next(&mut self) -> Link<Self> {
65+
mem::replace(self.next_mut(), Link::none())
66+
}
67+
}
68+
69+
//-----------------------------------------------------------------------------
70+
// Implementations
71+
//-----------------------------------------------------------------------------
72+
73+
// ===== impl List =====
74+
75+
impl<T, Node, R> List<T, Node, R> {
76+
/// Create a new `List` with 0 elements.
77+
pub const fn new() -> Self {
78+
List {
79+
head: Link::none(),
80+
len: 0,
81+
_elem_ty: PhantomData,
82+
_ref_ty: PhantomData,
83+
}
84+
}
85+
86+
/// Returns the length of the list.
87+
#[inline]
88+
pub fn len(&self) -> usize {
89+
self.len
90+
}
91+
92+
/// Returns true if the list is empty, false otherwise.
93+
#[inline]
94+
pub fn is_empty(&self) -> bool {
95+
self.len == 0
96+
}
97+
98+
/// Borrows the first node of the list as an `Option`.
99+
///
100+
/// Note that this is distinct from `front`: this method
101+
/// borrows the head _node_, not the head _element_.
102+
///
103+
/// # Returns
104+
/// - `Some(&N)` if the list has elements
105+
/// - `None` if the list is empty.
106+
#[inline]
107+
pub fn peek(&self) -> Option<&Node> {
108+
self.head.as_ref()
109+
}
110+
111+
/// Mutably borrows the head node of the list as an `Option`
112+
///
113+
/// # Returns
114+
/// - `Some(&mut Node)` if the list has elements
115+
/// - `None` if the list is empty.
116+
#[inline]
117+
pub fn peek_mut(&mut self) -> Option<&mut Node> {
118+
self.head.as_mut()
119+
}
120+
}
121+
122+
impl<T, Node, Ref> List<T, Node, Ref>
123+
where
124+
Node: Linked,
125+
Ref: OwningRef<Node>,
126+
Ref: DerefMut,
127+
{
128+
/// Push a node to the list.
129+
pub fn push_node(&mut self, mut node: Ref) -> &mut Self {
130+
unsafe {
131+
*node.next_mut() = self.head;
132+
let node = Link::from_owning_ref(node);
133+
self.head = node;
134+
self.len += 1;
135+
};
136+
self
137+
}
138+
}
139+
140+
impl<T, Node, Ref> List<T, Node, Ref>
141+
where
142+
Node: Linked,
143+
Ref: OwningRef<Node>,
144+
{
145+
/// Pop a node from the list.
146+
pub fn pop_node(&mut self) -> Option<Ref> {
147+
unsafe {
148+
self.head.as_ptr().map(|node| {
149+
self.head = (*node).take_next();
150+
self.len -= 1;
151+
Ref::from_ptr(node as *const Node)
152+
})
153+
}
154+
}
155+
}
156+
157+
impl<T, Node, R> List<T, Node, R>
158+
where
159+
Node: AsRef<T>,
160+
{
161+
/// Borrows the head item of the list as an `Option`
162+
///
163+
/// # Returns
164+
/// - `Some(&T)` if the list has elements
165+
/// - `None` if the list is empty.
166+
#[inline]
167+
pub fn front(&self) -> Option<&T> {
168+
self.peek().map(Node::as_ref)
169+
}
170+
}
171+
172+
impl<T, Node, R> List<T, Node, R>
173+
where
174+
Node: AsMut<T>,
175+
{
176+
/// Mutably borrows the head element of the list as an `Option`
177+
///
178+
/// # Returns
179+
/// - `Some(&mut T)` if the list has elements
180+
/// - `None` if the list is empty.
181+
#[inline]
182+
pub fn head_mut(&mut self) -> Option<&mut T> {
183+
self.peek_mut().map(Node::as_mut)
184+
}
185+
}
186+
187+
#[cfg(all(
188+
feature = "alloc",
189+
not(any(feature = "std", test))
190+
))]
191+
use alloc::boxed::Box;
192+
#[cfg(any(feature = "std", test))]
193+
use std::boxed::Box;
194+
195+
196+
#[cfg(any(feature = "alloc", feature = "std", test))]
197+
impl<T, Node> List<T, Node, Box<Node>>
198+
where
199+
Node: From<T>,
200+
Node: Linked,
201+
{
202+
/// Push an item to the list.
203+
#[inline]
204+
pub fn push(&mut self, item: T) -> &mut Self {
205+
self.push_node(Box::new(Node::from(item)))
206+
}
207+
}
208+
209+
#[cfg(any(feature = "alloc", feature = "std", test))]
210+
impl<T, Node> List<T, Node, Box<Node>>
211+
where
212+
Node: Linked,
213+
Node: Into<T>,
214+
{
215+
/// Pop an item from the list.
216+
#[inline]
217+
pub fn pop(&mut self) -> Option<T> {
218+
self.pop_node().map(|b| (*b).into())
219+
}
220+
}

0 commit comments

Comments
 (0)