Skip to content

Commit df447b7

Browse files
committed
linked list support push front
-------- Implementing push_front in a circular doubly linked list is very simple. It behaves the same as pushback, and only requires updating the head. Signed-off-by: guoweikang <[email protected]>
1 parent d18c1d0 commit df447b7

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/linked_list.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,20 @@ impl<G: GetLinksWrapped> List<G> {
161161
}
162162
}
163163

164+
/// Adds the given object to the first (front) of the list.
165+
///
166+
/// It is dropped if it's already on this (or another) list; this can happen for
167+
/// reference-counted objects, so dropping means decrementing the reference count.
168+
pub fn push_front(&mut self, data: G::Wrapped) {
169+
let ptr = data.into_pointer();
170+
171+
// SAFETY: We took ownership of the entry, so it is safe to insert it.
172+
if !unsafe { self.list.push_front(ptr.as_ref()) } {
173+
// If insertion failed, rebuild object so that it can be freed.
174+
unsafe { G::Wrapped::from_pointer(ptr) };
175+
}
176+
}
177+
164178
/// Inserts the given object after `existing`.
165179
///
166180
/// It is dropped if it's already on this (or another) list; this can happen for

src/raw_list.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ impl<G: GetLinks> RawList<G> {
152152
true
153153
}
154154

155-
fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
155+
fn push_back_internal(&mut self, new: &G::EntryType, front: bool) -> bool {
156156
let links = G::get_links(new);
157157
if !links.acquire_for_insertion() {
158158
// Nothing to do if already inserted.
@@ -164,7 +164,13 @@ impl<G: GetLinks> RawList<G> {
164164
let new_ptr = Some(NonNull::from(new));
165165
match self.back() {
166166
// SAFETY: `back` is valid as the list cannot change.
167-
Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
167+
Some(back) => {
168+
self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr);
169+
// if push front, update head
170+
if front {
171+
self.head = new_ptr;
172+
}
173+
}
168174
None => {
169175
self.head = new_ptr;
170176
new_entry.next = new_ptr;
@@ -175,7 +181,11 @@ impl<G: GetLinks> RawList<G> {
175181
}
176182

177183
pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
178-
self.push_back_internal(new)
184+
self.push_back_internal(new, false)
185+
}
186+
187+
pub(crate) unsafe fn push_front(&mut self, new: &G::EntryType) -> bool {
188+
self.push_back_internal(new, true)
179189
}
180190

181191
fn remove_internal(&mut self, data: &G::EntryType) -> bool {
@@ -538,6 +548,21 @@ mod tests {
538548
}
539549
}
540550

551+
#[test]
552+
fn test_push_front() {
553+
const MAX: usize = 10;
554+
let v = build_vector(MAX);
555+
let mut list = super::RawList::<Example>::new();
556+
557+
for n in 1..=MAX {
558+
// SAFETY: The entry was allocated above, it's not in any lists yet, is never moved,
559+
// and outlives the list.
560+
println!("push front: {}", MAX - n);
561+
unsafe { list.push_front(&v[MAX - n]) };
562+
assert_list_contents(&v[MAX - n..MAX], &list);
563+
}
564+
}
565+
541566
#[test]
542567
fn test_one_removal() {
543568
test_each_element(1, 10, |v, list, i, _| {

0 commit comments

Comments
 (0)