diff options
Diffstat (limited to 'src/xor_linked_list.rs')
-rw-r--r-- | src/xor_linked_list.rs | 310 |
1 files changed, 253 insertions, 57 deletions
diff --git a/src/xor_linked_list.rs b/src/xor_linked_list.rs index d5c2ca3..4b8bd28 100644 --- a/src/xor_linked_list.rs +++ b/src/xor_linked_list.rs @@ -19,8 +19,10 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use crate::link_ops::{self, DefaultLinkOps}; use crate::pointer_ops::PointerOps; use crate::singly_linked_list::SinglyLinkedListOps; -use crate::unchecked_option::UncheckedOptionExt; use crate::Adapter; +// Necessary for Rust 1.56 compatability +#[allow(unused_imports)] +use crate::unchecked_option::UncheckedOptionExt; // ============================================================================= // XorLinkedListOps @@ -466,7 +468,7 @@ unsafe fn link_between<T: XorLinkedListOps>( } // ============================================================================= -// Cursor, CursorMut +// Cursor, CursorMut, CursorOwning // ============================================================================= /// A cursor which provides read-only access to a `XorLinkedList`. @@ -525,7 +527,7 @@ where where <A::PointerOps as PointerOps>::Pointer: Clone, { - let raw_pointer = self.get()? as *const <A::PointerOps as PointerOps>::Value; + let raw_pointer = unsafe { self.list.adapter.get_value(self.current?) }; Some(unsafe { crate::pointer_ops::clone_pointer_from_raw(self.list.adapter.pointer_ops(), raw_pointer) }) @@ -1082,6 +1084,72 @@ where } } +/// A cursor with ownership over the `XorLinkedList` it points into. +pub struct CursorOwning<A: Adapter> +where + A::LinkOps: XorLinkedListOps, +{ + current: Option<<A::LinkOps as link_ops::LinkOps>::LinkPtr>, + prev: Option<<A::LinkOps as link_ops::LinkOps>::LinkPtr>, + next: Option<<A::LinkOps as link_ops::LinkOps>::LinkPtr>, + list: XorLinkedList<A>, +} + +impl<A: Adapter> CursorOwning<A> +where + A::LinkOps: XorLinkedListOps, +{ + /// Consumes self and returns the inner `XorLinkedList`. + #[inline] + pub fn into_inner(self) -> XorLinkedList<A> { + self.list + } + + /// Returns a read-only cursor pointing to the current element. + /// + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorOwning`, which means it cannot outlive the `CursorOwning` and that the + /// `CursorOwning` is frozen for the lifetime of the `Cursor`. + /// + /// Mutations of the returned cursor are _not_ reflected in the original. + #[inline] + pub fn as_cursor(&self) -> Cursor<'_, A> { + Cursor { + current: self.current, + prev: self.prev, + next: self.next, + list: &self.list, + } + } + + /// Perform action with mutable reference to the cursor. + /// + /// All mutations of the cursor are reflected in the original. + #[inline] + pub fn with_cursor_mut<T>(&mut self, f: impl FnOnce(&mut CursorMut<'_, A>) -> T) -> T { + let mut cursor = CursorMut { + current: self.current, + prev: self.prev, + next: self.next, + list: &mut self.list, + }; + + let ret = f(&mut cursor); + + self.current = cursor.current; + self.prev = cursor.prev; + self.next = cursor.next; + + ret + } +} +unsafe impl<A: Adapter> Send for CursorOwning<A> +where + XorLinkedList<A>: Send, + A::LinkOps: XorLinkedListOps, +{ +} + // ============================================================================= // XorLinkedList // ============================================================================= @@ -1178,6 +1246,17 @@ where } } + /// Returns a null `CursorOwning` for this list. + #[inline] + pub fn cursor_owning(self) -> CursorOwning<A> { + CursorOwning { + current: None, + prev: self.tail, + next: self.head, + list: self, + } + } + /// Creates a `Cursor` from a pointer to an element and a pointer to the previous element. /// /// # Safety @@ -1234,6 +1313,34 @@ where } } + /// Creates a `CursorOwning` from a pointer to an element and a pointer to the previous element. + /// + /// # Safety + /// + /// `ptr` must be a pointer to an object that is part of this list. + /// `prev` must be a pointer to an object that is the previous object in this list (null for the head) + #[inline] + pub unsafe fn cursor_owning_from_ptr_and_prev( + self, + ptr: *const <A::PointerOps as PointerOps>::Value, + prev: *const <A::PointerOps as PointerOps>::Value, + ) -> CursorOwning<A> { + let current = self.adapter.get_link(ptr); + let prev = if !prev.is_null() { + Some(self.adapter.get_link(prev)) + } else { + None + }; + let next = self.adapter.link_ops().next(current, prev); + + CursorOwning { + current: Some(current), + prev, + next, + list: self, + } + } + /// Creates a `Cursor` from a pointer to an element and a pointer to the next element. /// /// # Safety @@ -1290,6 +1397,34 @@ where } } + /// Creates a `CursorOwning` from a pointer to an element and a pointer to the next element. + /// + /// # Safety + /// + /// `ptr` must be a pointer to an object that is part of this list. + /// `next` must be a pointer to an object that is the next object in this list (null for the tail) + #[inline] + pub unsafe fn cursor_owning_from_ptr_and_next( + self, + ptr: *const <A::PointerOps as PointerOps>::Value, + next: *const <A::PointerOps as PointerOps>::Value, + ) -> CursorOwning<A> { + let current = self.adapter.get_link(ptr); + let next = if !next.is_null() { + Some(self.adapter.get_link(next)) + } else { + None + }; + let prev = self.adapter.link_ops().prev(current, next); + + CursorOwning { + current: Some(current), + prev, + next, + list: self, + } + } + /// Returns a `Cursor` pointing to the first element of the list. If the /// list is empty then a null cursor is returned. #[inline] @@ -1308,6 +1443,15 @@ where cursor } + /// Returns a `CursorOwning` pointing to the first element of the list. If the + /// the list is empty then a null cursor is returned. + #[inline] + pub fn front_owning(self) -> CursorOwning<A> { + let mut cursor = self.cursor_owning(); + cursor.with_cursor_mut(|c| c.move_next()); + cursor + } + /// Returns a `Cursor` pointing to the last element of the list. If the list /// is empty then a null cursor is returned. #[inline] @@ -1326,6 +1470,15 @@ where cursor } + /// Returns a `CursorOwning` pointing to the last element of the list. If the + /// list is empty then a null cursor is returned. + #[inline] + pub fn back_owning(self) -> CursorOwning<A> { + let mut cursor = self.cursor_owning(); + cursor.with_cursor_mut(|c| c.move_prev()); + cursor + } + /// Gets an iterator over the objects in the `XorLinkedList`. #[inline] pub fn iter(&self) -> Iter<'_, A> { @@ -1616,7 +1769,9 @@ where #[cfg(test)] mod tests { - use super::{Link, XorLinkedList}; + use crate::UnsafeRef; + + use super::{CursorOwning, Link, XorLinkedList}; use core::cell::Cell; use core::ptr; use std::boxed::Box; @@ -1635,24 +1790,29 @@ mod tests { write!(f, "{}", self.value) } } - intrusive_adapter!(ObjAdapter1 = Rc<Obj>: Obj { link1: Link }); - intrusive_adapter!(ObjAdapter2 = Rc<Obj>: Obj { link2: Link }); + intrusive_adapter!(RcObjAdapter1 = Rc<Obj>: Obj { link1: Link }); + intrusive_adapter!(RcObjAdapter2 = Rc<Obj>: Obj { link2: Link }); + intrusive_adapter!(UnsafeRefObjAdapter1 = UnsafeRef<Obj>: Obj { link1: Link }); - fn make_obj(value: u32) -> Rc<Obj> { - Rc::new(Obj { + fn make_rc_obj(value: u32) -> Rc<Obj> { + Rc::new(make_obj(value)) + } + + fn make_obj(value: u32) -> Obj { + Obj { link1: Link::new(), link2: Link::default(), value, - }) + } } #[test] fn test_link() { - let a = make_obj(1); + let a = make_rc_obj(1); assert!(!a.link1.is_linked()); assert!(!a.link2.is_linked()); - let mut b = XorLinkedList::<ObjAdapter1>::default(); + let mut b = XorLinkedList::<RcObjAdapter1>::default(); assert!(b.is_empty()); b.cursor_mut().insert_after(a.clone()); @@ -1673,11 +1833,11 @@ mod tests { #[test] fn test_cursor() { - let a = make_obj(1); - let b = make_obj(2); - let c = make_obj(3); + let a = make_rc_obj(1); + let b = make_rc_obj(2); + let c = make_rc_obj(3); - let mut l = XorLinkedList::new(ObjAdapter1::new()); + let mut l = XorLinkedList::new(RcObjAdapter1::new()); let mut cur = l.cursor_mut(); assert!(cur.is_null()); assert!(cur.get().is_none()); @@ -1755,12 +1915,38 @@ mod tests { } #[test] + fn test_cursor_owning() { + struct Container { + cur: CursorOwning<RcObjAdapter1>, + } + + let mut l = XorLinkedList::new(RcObjAdapter1::new()); + l.push_back(make_rc_obj(1)); + l.push_back(make_rc_obj(2)); + l.push_back(make_rc_obj(3)); + l.push_back(make_rc_obj(4)); + let mut con = Container { + cur: l.cursor_owning(), + }; + assert!(con.cur.as_cursor().is_null()); + + con.cur = con.cur.into_inner().front_owning(); + assert_eq!(con.cur.as_cursor().get().unwrap().value, 1); + + con.cur.with_cursor_mut(|c| c.move_next()); + assert_eq!(con.cur.as_cursor().get().unwrap().value, 2); + + con.cur = con.cur.into_inner().back_owning(); + assert_eq!(con.cur.as_cursor().get().unwrap().value, 4); + } + + #[test] fn test_push_pop() { - let a = make_obj(1); - let b = make_obj(2); - let c = make_obj(3); + let a = make_rc_obj(1); + let b = make_rc_obj(2); + let c = make_rc_obj(3); - let mut l = XorLinkedList::new(ObjAdapter1::new()); + let mut l = XorLinkedList::new(RcObjAdapter1::new()); l.push_front(a); assert_eq!(l.iter().map(|x| x.value).collect::<Vec<_>>(), [1]); l.push_front(b); @@ -1781,14 +1967,14 @@ mod tests { #[test] fn test_split_splice() { - let mut l1 = XorLinkedList::new(ObjAdapter1::new()); - let mut l2 = XorLinkedList::new(ObjAdapter1::new()); - let mut l3 = XorLinkedList::new(ObjAdapter1::new()); - - let a = make_obj(1); - let b = make_obj(2); - let c = make_obj(3); - let d = make_obj(4); + let mut l1 = XorLinkedList::new(RcObjAdapter1::new()); + let mut l2 = XorLinkedList::new(RcObjAdapter1::new()); + let mut l3 = XorLinkedList::new(RcObjAdapter1::new()); + + let a = make_rc_obj(1); + let b = make_rc_obj(2); + let c = make_rc_obj(3); + let d = make_rc_obj(4); l1.cursor_mut().insert_before(a); l1.cursor_mut().insert_before(b); l1.cursor_mut().insert_before(c); @@ -1872,11 +2058,11 @@ mod tests { #[test] fn test_iter() { - let mut l = XorLinkedList::new(ObjAdapter1::new()); - let a = make_obj(1); - let b = make_obj(2); - let c = make_obj(3); - let d = make_obj(4); + let mut l = XorLinkedList::new(RcObjAdapter1::new()); + let a = make_rc_obj(1); + let b = make_rc_obj(2); + let c = make_rc_obj(3); + let d = make_rc_obj(4); l.cursor_mut().insert_before(a.clone()); l.cursor_mut().insert_before(b.clone()); l.cursor_mut().insert_before(c.clone()); @@ -1979,12 +2165,12 @@ mod tests { #[test] fn test_multi_list() { - let mut l1 = XorLinkedList::new(ObjAdapter1::new()); - let mut l2 = XorLinkedList::new(ObjAdapter2::new()); - let a = make_obj(1); - let b = make_obj(2); - let c = make_obj(3); - let d = make_obj(4); + let mut l1 = XorLinkedList::new(RcObjAdapter1::new()); + let mut l2 = XorLinkedList::new(RcObjAdapter2::new()); + let a = make_rc_obj(1); + let b = make_rc_obj(2); + let c = make_rc_obj(3); + let d = make_rc_obj(4); l1.cursor_mut().insert_before(a.clone()); l1.cursor_mut().insert_before(b.clone()); l1.cursor_mut().insert_before(c.clone()); @@ -1998,46 +2184,56 @@ mod tests { } #[test] - fn test_force_unlink() { - let mut l = XorLinkedList::new(ObjAdapter1::new()); - let a = make_obj(1); - let b = make_obj(2); - let c = make_obj(3); + fn test_fast_clear_force_unlink() { + let mut l = XorLinkedList::new(UnsafeRefObjAdapter1::new()); + let a = UnsafeRef::from_box(Box::new(make_obj(1))); + let b = UnsafeRef::from_box(Box::new(make_obj(2))); + let c = UnsafeRef::from_box(Box::new(make_obj(3))); l.cursor_mut().insert_before(a.clone()); l.cursor_mut().insert_before(b.clone()); l.cursor_mut().insert_before(c.clone()); l.fast_clear(); assert!(l.is_empty()); - assert!(a.link1.is_linked()); - assert!(b.link1.is_linked()); - assert!(c.link1.is_linked()); + unsafe { + assert!(a.link1.is_linked()); + assert!(b.link1.is_linked()); + assert!(c.link1.is_linked()); + a.link1.force_unlink(); b.link1.force_unlink(); c.link1.force_unlink(); + + assert!(l.is_empty()); + + assert!(!a.link1.is_linked()); + assert!(!b.link1.is_linked()); + assert!(!c.link1.is_linked()); + } + + unsafe { + UnsafeRef::into_box(a); + UnsafeRef::into_box(b); + UnsafeRef::into_box(c); } - assert!(l.is_empty()); - assert!(!a.link1.is_linked()); - assert!(!b.link1.is_linked()); - assert!(!c.link1.is_linked()); } #[test] fn test_reverse() { - let mut l = XorLinkedList::new(ObjAdapter1::new()); + let mut l = XorLinkedList::new(RcObjAdapter1::new()); - l.push_back(make_obj(1)); - l.push_back(make_obj(2)); - l.push_back(make_obj(3)); - l.push_back(make_obj(4)); + l.push_back(make_rc_obj(1)); + l.push_back(make_rc_obj(2)); + l.push_back(make_rc_obj(3)); + l.push_back(make_rc_obj(4)); assert_eq!(l.iter().map(|x| x.value).collect::<Vec<_>>(), [1, 2, 3, 4]); l.reverse(); assert_eq!(l.iter().map(|x| x.value).collect::<Vec<_>>(), [4, 3, 2, 1]); - l.push_back(make_obj(5)); - l.push_back(make_obj(6)); + l.push_back(make_rc_obj(5)); + l.push_back(make_rc_obj(6)); assert_eq!( l.iter().map(|x| x.value).collect::<Vec<_>>(), [4, 3, 2, 1, 5, 6] |