Skip to content

Commit a981be7

Browse files
committed
add head/tail methods to linked list mutable cursor
1 parent 5d0fae5 commit a981be7

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

library/alloc/src/collections/linked_list.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,128 @@ impl<'a, T> CursorMut<'a, T> {
15061506
self.index = 0;
15071507
unsafe { self.list.split_off_before_node(self.current, split_off_idx) }
15081508
}
1509+
1510+
/// Appends an element to the front of the cursor's parent list. The node
1511+
/// that the cursor points to is unchanged, even if it is the "ghost" node.
1512+
///
1513+
/// This operation should compute in O(1) time.
1514+
// `push_front` continues to point to "ghost" when it addes a node to mimic
1515+
// the behavior of `insert_before` on an empty list.
1516+
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1517+
pub fn push_front(&mut self, elt: T) {
1518+
// Safety: We know that `push_front` does not change the position in
1519+
// memory of other nodes. This ensures that `self.current` remains
1520+
// valid.
1521+
self.list.push_front(elt);
1522+
self.index += 1;
1523+
}
1524+
1525+
/// Appends an element to the back of the cursor's parent list. The node
1526+
/// that the cursor points to is unchanged, even if it is the "ghost" node.
1527+
///
1528+
/// This operation should compute in O(1) time.
1529+
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1530+
pub fn push_back(&mut self, elt: T) {
1531+
// Safety: We know that `push_back` does not change the position in
1532+
// memory of other nodes. This ensures that `self.current` remains
1533+
// valid.
1534+
self.list.push_back(elt);
1535+
}
1536+
1537+
/// Removes the first element from the cursor's parent list and returns it,
1538+
/// or None if the list is empty. The element the cursor points to remains
1539+
/// unchanged, unless it was pointing to the front element. In that case, it
1540+
/// points to the new front element.
1541+
///
1542+
/// This operation should compute in O(1) time.
1543+
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1544+
pub fn pop_front(&mut self) -> Option<T> {
1545+
// We can't check if current is empty, we must check the list directly.
1546+
// It is possible for `self.current == None` and the list to be
1547+
// non-empty.
1548+
if self.list.is_empty() {
1549+
None
1550+
} else {
1551+
// We can't point to the node that we pop. Copying the behavior of
1552+
// `remove_current`, we move on the the next node in the sequence.
1553+
// If the list is of length 1 then we end pointing to the "ghost"
1554+
// node, which is expected.
1555+
if self.list.head == self.current {
1556+
self.move_next();
1557+
}
1558+
// We always need to change the index since `head` comes before any
1559+
// other element.
1560+
self.index.checked_sub(1).unwrap_or(0);
1561+
self.list.pop_front()
1562+
}
1563+
}
1564+
1565+
/// Removes the last element from the cursor's parent list and returns it,
1566+
/// or None if the list is empty. The element the cursor points to remains
1567+
/// unchanged, unless it was pointing to the back element. In that case, it
1568+
/// points to the new back element.
1569+
///
1570+
/// This operation should compute in O(1) time.
1571+
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1572+
pub fn pop_back(&mut self) -> Option<T> {
1573+
if self.list.is_empty() {
1574+
None
1575+
} else {
1576+
if self.list.tail == self.current {
1577+
self.move_prev()
1578+
}
1579+
// We don't need to change the index since `current` points to a
1580+
// node before `tail`.
1581+
self.list.pop_back()
1582+
}
1583+
}
1584+
1585+
/// Provides a reference to the front element of the cursor's parent list,
1586+
/// or None if the list is empty.
1587+
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1588+
pub fn front(&self) -> Option<&T> {
1589+
self.list.front()
1590+
}
1591+
1592+
/// Provides a mutable reference to the front element of the cursor's
1593+
/// parent list, or None if the list is empty.
1594+
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1595+
pub fn front_mut(&mut self) -> Option<&mut T> {
1596+
self.list.front_mut()
1597+
}
1598+
1599+
/// Provides a reference to the back element of the cursor's parent list,
1600+
/// or None if the list is empty.
1601+
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1602+
pub fn back(&self) -> Option<&T> {
1603+
self.list.back()
1604+
}
1605+
1606+
/// Provides a mutable reference to back element of the cursor's parent
1607+
/// list, or `None` if the list is empty.
1608+
///
1609+
/// # Examples
1610+
/// Building and mutating a list with a cursor, then getting the back element:
1611+
/// ```
1612+
/// #![feature(linked_list_cursors)]
1613+
/// use std::collections::LinkedList;
1614+
/// let mut dl = LinkedList::new();
1615+
/// dl.push_front(3);
1616+
/// dl.push_front(2);
1617+
/// dl.push_front(1);
1618+
/// let mut cursor = dl.cursor_front_mut();
1619+
/// *cursor.current().unwrap() = 99;
1620+
/// *cursor.back_mut().unwrap() = 0;
1621+
/// let mut contents = dl.into_iter();
1622+
/// assert_eq!(contents.next(), Some(99));
1623+
/// assert_eq!(contents.next(), Some(2));
1624+
/// assert_eq!(contents.next(), Some(0));
1625+
/// assert_eq!(contents.next(), None);
1626+
/// ```
1627+
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1628+
pub fn back_mut(&mut self) -> Option<&mut T> {
1629+
self.list.back_mut()
1630+
}
15091631
}
15101632

15111633
/// An iterator produced by calling `drain_filter` on LinkedList.

library/alloc/src/collections/linked_list/tests.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,3 +428,35 @@ fn test_cursor_mut_insert() {
428428
check_links(&m);
429429
assert_eq!(m.iter().cloned().collect::<Vec<_>>(), &[200, 201, 202, 203, 1, 100, 101]);
430430
}
431+
432+
#[test]
433+
fn test_cursor_push_front_back() {
434+
let mut ll: LinkedList<u32> = LinkedList::new();
435+
ll.extend(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
436+
let mut c = ll.cursor_front_mut();
437+
assert_eq!(c.current(), Some(&mut 1));
438+
assert_eq!(c.index(), Some(0));
439+
c.push_front(0);
440+
assert_eq!(c.current(), Some(&mut 1));
441+
assert_eq!(c.peek_prev(), Some(&mut 0));
442+
assert_eq!(c.index(), Some(1));
443+
c.push_back(11);
444+
drop(c);
445+
assert_eq!(ll, (0..12).collect());
446+
check_links(&ll);
447+
}
448+
449+
#[test]
450+
fn test_cursor_pop_front_back() {
451+
let mut ll: LinkedList<u32> = LinkedList::new();
452+
ll.extend(&[1, 2, 3, 4, 5, 6]);
453+
let mut c = ll.cursor_back_mut();
454+
assert_eq!(c.pop_front(), Some(1));
455+
c.move_prev();
456+
c.move_prev();
457+
c.move_prev();
458+
assert_eq!(c.pop_back(), Some(6));
459+
drop(c);
460+
assert_eq!(ll, (2..6).collect());
461+
check_links(&ll);
462+
}

0 commit comments

Comments
 (0)