diff --git a/cordyceps/src/list.rs b/cordyceps/src/list.rs index 35651200..3c5dfeb2 100644 --- a/cordyceps/src/list.rs +++ b/cordyceps/src/list.rs @@ -205,6 +205,7 @@ use core::{ pub struct List { head: Link, tail: Link, + len: usize, } /// Links to other nodes in a [`List`]. @@ -250,21 +251,37 @@ impl List { List { head: None, tail: None, + len: 0, } } /// Returns `true` if this list is empty. + #[inline] pub fn is_empty(&self) -> bool { if self.head.is_none() { debug_assert!( self.tail.is_none(), "inconsistent state: a list had a tail but no head!" ); + debug_assert_eq!( + self.len, 0, + "inconsistent state: a list was empty, but its length was not zero" + ); return true; } + debug_assert_ne!( + self.len, 0, + "inconsistent state: a list was not empty, but its length was zero" + ); false } + + /// Returns the number of elements in the list. + #[inline] + pub fn len(&self) -> usize { + self.len + } } impl> + ?Sized> List { @@ -277,10 +294,19 @@ impl> + ?Sized> List { self.tail.is_none(), "if the linked list's head is null, the tail must also be null" ); + assert_eq!( + self.len, 0, + "if a linked list's head is null, its length must be 0" + ); return; } }; + assert_ne!( + self.len, 0, + "if a linked list's head is not null, its length must be greater than 0" + ); + let tail = self .tail .expect("if the linked list has a head, it must also have a tail"); @@ -307,12 +333,16 @@ impl> + ?Sized> List { } let mut curr = Some(head); + let mut actual_len = 0; while let Some(node) = curr { let links = unsafe { T::links(node) }; let links = unsafe { links.as_ref() }; links.assert_valid(head_links, tail_links); curr = links.next(); + actual_len += 1; } + + assert_eq!(self.len, actual_len); } /// Appends an item to the head of the list. @@ -336,6 +366,7 @@ impl> + ?Sized> List { self.tail = Some(ptr); } + self.len += 1; // tracing::trace!(?self, "push_front: pushed"); } @@ -355,11 +386,14 @@ impl> + ?Sized> List { if self.head.is_none() { self.head = Some(ptr); } + + self.len += 1; } /// Remove an item from the head of the list pub fn pop_front(&mut self) -> Option { let head = self.head?; + self.len -= 1; unsafe { let mut head_links = T::links(head); @@ -378,6 +412,8 @@ impl> + ?Sized> List { /// Removes an item from the tail of the list. pub fn pop_back(&mut self) -> Option { let tail = self.tail?; + self.len -= 1; + unsafe { let mut tail_links = T::links(tail); // tracing::trace!(?self, tail.addr = ?tail, tail.links = ?tail_links, "pop_back"); @@ -433,6 +469,7 @@ impl> + ?Sized> List { self.tail = prev; } + self.len -= 1; // tracing::trace!(?self, item.addr = ?item, "remove: done"); Some(T::from_ptr(item)) } @@ -1209,6 +1246,7 @@ mod tests { } } } + assert_eq!(ll.len(), reference.len()); ll.assert_valid(); } }