Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update version to 0.2.1 #2

Merged
merged 2 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "linked_list_r4l"
version = "0.2.0"
version = "0.2.1"
edition = "2021"
authors = ["Wedson Almeida Filho <[email protected]>", "WeiKang Guo <[email protected]>"]
description = "Linked lists that supports arbitrary removal in constant time"
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
mod linked_list;
mod raw_list;
pub use linked_list::List;
pub use raw_list::{GetLinks, Links};
pub use raw_list::{GetLinks, Links, RawList};

#[macro_export(local_inner_macros)]
#[doc(hidden)]
Expand Down
14 changes: 14 additions & 0 deletions src/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,20 @@ impl<G: GetLinksWrapped> List<G> {
}
}

/// Adds the given object to the first (front) of the list.
///
/// It is dropped if it's already on this (or another) list; this can happen for
/// reference-counted objects, so dropping means decrementing the reference count.
pub fn push_front(&mut self, data: G::Wrapped) {
let ptr = data.into_pointer();

// SAFETY: We took ownership of the entry, so it is safe to insert it.
if !unsafe { self.list.push_front(ptr.as_ref()) } {
// If insertion failed, rebuild object so that it can be freed.
unsafe { G::Wrapped::from_pointer(ptr) };
}
}

/// Inserts the given object after `existing`.
///
/// It is dropped if it's already on this (or another) list; this can happen for
Expand Down
81 changes: 57 additions & 24 deletions src/raw_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,23 @@ impl<T: ?Sized> ListEntry<T> {
/// # Invariants
///
/// The links of objects added to a list are owned by the list.
pub(crate) struct RawList<G: GetLinks> {
pub struct RawList<G: GetLinks> {
head: Option<NonNull<G::EntryType>>,
}

impl<G: GetLinks> RawList<G> {
pub(crate) const fn new() -> Self {
/// Constructs a new empty RawList.
pub const fn new() -> Self {
Self { head: None }
}

/// Returns an iterator for the list starting at the first entry.
pub(crate) fn iter(&self) -> Iterator<'_, G> {
pub fn iter(&self) -> Iterator<'_, G> {
Iterator::new(self.cursor_front(), self.cursor_back())
}

pub(crate) const fn is_empty(&self) -> bool {
/// Returns whether the RawList is empty.
pub const fn is_empty(&self) -> bool {
self.head.is_none()
}

Expand Down Expand Up @@ -135,11 +137,7 @@ impl<G: GetLinks> RawList<G> {
/// # Safety
///
/// Callers must ensure that `existing` points to a valid entry that is on the list.
pub(crate) unsafe fn insert_after(
&mut self,
existing: &G::EntryType,
new: &G::EntryType,
) -> bool {
pub unsafe fn insert_after(&mut self, existing: &G::EntryType, new: &G::EntryType) -> bool {
let links = G::get_links(new);
if !links.acquire_for_insertion() {
// Nothing to do if already inserted.
Expand All @@ -152,7 +150,7 @@ impl<G: GetLinks> RawList<G> {
true
}

fn push_back_internal(&mut self, new: &G::EntryType) -> bool {
fn push_back_internal(&mut self, new: &G::EntryType, front: bool) -> bool {
let links = G::get_links(new);
if !links.acquire_for_insertion() {
// Nothing to do if already inserted.
Expand All @@ -164,7 +162,13 @@ impl<G: GetLinks> RawList<G> {
let new_ptr = Some(NonNull::from(new));
match self.back() {
// SAFETY: `back` is valid as the list cannot change.
Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr),
Some(back) => {
self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr);
// if push front, update head
if front {
self.head = new_ptr;
}
}
None => {
self.head = new_ptr;
new_entry.next = new_ptr;
Expand All @@ -174,8 +178,22 @@ impl<G: GetLinks> RawList<G> {
true
}

pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
self.push_back_internal(new)
/// Adds the given object to the end (back) of the list.
///
/// Rawlist will save the reference as node ptr.
/// The caller must ensure the validity of the reference while it is on
/// the linked list.
pub unsafe fn push_back(&mut self, new: &G::EntryType) -> bool {
self.push_back_internal(new, false)
}

/// Adds the given object to the first (front) of the list.
///
/// Rawlist will save the reference as node ptr.
/// The caller must ensure the validity of the reference while it is on
/// the linked list.
pub unsafe fn push_front(&mut self, new: &G::EntryType) -> bool {
self.push_back_internal(new, true)
}

fn remove_internal(&mut self, data: &G::EntryType) -> bool {
Expand Down Expand Up @@ -222,7 +240,7 @@ impl<G: GetLinks> RawList<G> {
///
/// Callers must ensure that `data` is either on this list or in no list. It being on another
/// list leads to memory unsafety.
pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
pub unsafe fn remove(&mut self, data: &G::EntryType) -> bool {
self.remove_internal(data)
}

Expand All @@ -234,7 +252,7 @@ impl<G: GetLinks> RawList<G> {
}

/// Get and Remove the first element of the list.
pub(crate) fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
pub fn pop_front(&mut self) -> Option<NonNull<G::EntryType>> {
self.pop_front_internal()
}

Expand All @@ -260,7 +278,7 @@ impl<G: GetLinks> RawList<G> {
}

/// Returns a mut cursor starting on the first element of the list.
pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> {
CursorMut::new(self, self.front())
}
}
Expand Down Expand Up @@ -351,7 +369,7 @@ impl<'a, G: GetLinks> Cursor<'a, G> {
}
}

pub(crate) struct CursorMut<'a, G: GetLinks> {
pub struct CursorMut<'a, G: GetLinks> {
cursor: CommonCursor<G>,
list: &'a mut RawList<G>,
}
Expand All @@ -364,42 +382,42 @@ impl<'a, G: GetLinks> CursorMut<'a, G> {
}
}

pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> {
pub fn current(&mut self) -> Option<&mut G::EntryType> {
let cur = self.cursor.cur?;
// SAFETY: Objects must be kept alive while on the list.
Some(unsafe { &mut *cur.as_ptr() })
}

/// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It
/// returns a raw pointer to the removed element (if one is removed).
pub(crate) fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
pub fn remove_current(&mut self) -> Option<NonNull<G::EntryType>> {
let entry = self.cursor.cur?;
self.cursor.move_next(self.list);
// SAFETY: The entry is on the list as we just got it from there and it cannot change.
unsafe { self.list.remove(entry.as_ref()) };
Some(entry)
}

pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> {
pub fn peek_next(&mut self) -> Option<&mut G::EntryType> {
let mut new = CommonCursor::new(self.cursor.cur);
new.move_next(self.list);
// SAFETY: Objects must be kept alive while on the list.
Some(unsafe { &mut *new.cur?.as_ptr() })
}

pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> {
let mut new = CommonCursor::new(self.cursor.cur);
new.move_prev(self.list);
// SAFETY: Objects must be kept alive while on the list.
Some(unsafe { &mut *new.cur?.as_ptr() })
}

pub(crate) fn move_next(&mut self) {
pub fn move_next(&mut self) {
self.cursor.move_next(self.list);
}

#[allow(dead_code)]
pub(crate) fn move_prev(&mut self) {
pub fn move_prev(&mut self) {
self.cursor.move_prev(self.list);
}
}
Expand All @@ -413,7 +431,7 @@ impl<'a, G: GetLinks> iter::IntoIterator for &'a RawList<G> {
}

/// An iterator for the linked list.
pub(crate) struct Iterator<'a, G: GetLinks> {
pub struct Iterator<'a, G: GetLinks> {
cursor_front: Cursor<'a, G>,
cursor_back: Cursor<'a, G>,
}
Expand Down Expand Up @@ -538,6 +556,21 @@ mod tests {
}
}

#[test]
fn test_push_front() {
const MAX: usize = 10;
let v = build_vector(MAX);
let mut list = super::RawList::<Example>::new();

for n in 1..=MAX {
// SAFETY: The entry was allocated above, it's not in any lists yet, is never moved,
// and outlives the list.
println!("push front: {}", MAX - n);
unsafe { list.push_front(&v[MAX - n]) };
assert_list_contents(&v[MAX - n..MAX], &list);
}
}

#[test]
fn test_one_removal() {
test_each_element(1, 10, |v, list, i, _| {
Expand Down